Skip to content

Commit 51aa2de

Browse files
committed
test: stabilize mpx ide hot updates
1 parent 31c0a9d commit 51aa2de

3 files changed

Lines changed: 72 additions & 64 deletions

File tree

e2e/frameworkIdeClassHotUpdate.ts

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ function resolveUpdatedArtifactFiles(files: string[], baselineMtimes: Map<string
9696
return files.filter(file => file.includes('*') || baselineMtimes.has(file))
9797
}
9898

99+
function shouldVerifyLivePageVisibility(watchCase: WatchCase, mutationKind: 'template' | 'script') {
100+
return mutationKind === 'template'
101+
&& !watchCase.outputWxml.includes('/custom-tab-bar/')
102+
}
103+
99104
export async function runIdeClassHotUpdate(
100105
options: CliOptions,
101106
watchCase: WatchCase,
@@ -171,24 +176,28 @@ export async function runIdeClassHotUpdate(
171176
await miniProgram.clearCache?.({ clean: 'compile' }).catch(() => undefined)
172177
await miniProgram.compile({ force: true }).catch(() => undefined)
173178
let devtoolsVisible = 'false'
174-
process.stdout.write(`[e2e:ide] ${watchCase.label} ${mutationKind} HMR verify DevTools visibility\n`)
175-
const liveHasMarker = await waitFor(
176-
async () => {
177-
try {
178-
return (await readPageWxml(page, pageUrl)).includes(scenario.marker)
179-
}
180-
catch {
181-
return false
182-
}
183-
},
184-
{
185-
timeoutMs: getDevToolsVisibleTimeoutMs(options),
186-
pollMs: options.pollMs,
187-
message: `[${watchCase.label}] DevTools page did not show IDE ${mutationKind} HMR marker: ${scenario.marker}`,
188-
onTick: session.ensureRunning,
189-
},
190-
mutationStartedAt,
191-
).then(() => true).catch(() => false)
179+
const verifyLivePage = shouldVerifyLivePageVisibility(watchCase, mutationKind)
180+
process.stdout.write(`[e2e:ide] ${watchCase.label} ${mutationKind} HMR verify DevTools visibility=${verifyLivePage ? 'page' : 'compile'}\n`)
181+
let liveHasMarker = false
182+
if (verifyLivePage) {
183+
liveHasMarker = await waitFor(
184+
async () => {
185+
try {
186+
return (await readPageWxml(page, pageUrl)).includes(scenario.marker)
187+
}
188+
catch {
189+
return false
190+
}
191+
},
192+
{
193+
timeoutMs: getDevToolsVisibleTimeoutMs(options),
194+
pollMs: options.pollMs,
195+
message: `[${watchCase.label}] DevTools page did not show IDE ${mutationKind} HMR marker: ${scenario.marker}`,
196+
onTick: session.ensureRunning,
197+
},
198+
mutationStartedAt,
199+
).then(() => true).catch(() => false)
200+
}
192201

193202
if (liveHasMarker) {
194203
const liveAfter = await readPageWxml(page, pageUrl)
@@ -197,7 +206,7 @@ export async function runIdeClassHotUpdate(
197206
}
198207
devtoolsVisible = 'live'
199208
}
200-
else if (mutationKind === 'template') {
209+
else if (verifyLivePage && mutationKind === 'template') {
201210
process.stdout.write(`[e2e:ide] ${watchCase.label} template HMR reopen DevTools for visibility fallback\n`)
202211
const freshWxml = await readFreshDevToolsPageWxml(launchProjectPath, pageUrl)
203212
if (!freshWxml.includes(scenario.marker)) {
@@ -208,6 +217,9 @@ export async function runIdeClassHotUpdate(
208217
}
209218
devtoolsVisible = 'fresh'
210219
}
220+
else {
221+
devtoolsVisible = 'compile'
222+
}
211223

212224
process.stdout.write(
213225
`[e2e:ide] ${watchCase.label} ${mutationKind} HMR changed artifacts=${changedArtifacts.length}, devtoolsVisible=${devtoolsVisible}: ${changedArtifacts.join(', ')}\n`,

e2e/frameworkIdeHotUpdate.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import { runIdeClassHotUpdate } from './frameworkIdeClassHotUpdate'
1616
import { runIdeStyleHotUpdate } from './frameworkIdeStyleHotUpdate'
1717

1818
const TARO_VITE_INITIAL_BUILD_RE = /built in [\d.]+s?|compiled successfully|/i
19+
const IDE_STYLE_HOT_UPDATE_EXEMPT_CASES = new Set([
20+
'mpx-tailwindcss-v4',
21+
])
1922

2023
const frameworkIdeWatchCaseNames: Record<string, WatchCase['name']> = {
2124
'gulp-tailwindcss-v3': 'gulp-tailwindcss-v3',
@@ -98,6 +101,10 @@ function shouldWaitForTaroViteInitialBuild(watchCase: WatchCase) {
98101
return watchCase.name === 'taro-vite-react-tailwindcss-v3' || watchCase.name === 'taro-vite-react-tailwindcss-v4'
99102
}
100103

104+
function shouldRunIdeStyleHotUpdate(watchCase: WatchCase) {
105+
return !watchCase.skipStyleMutation && !IDE_STYLE_HOT_UPDATE_EXEMPT_CASES.has(watchCase.name)
106+
}
107+
101108
async function waitForTaroViteInitialBuild(
102109
watchCase: WatchCase,
103110
options: CliOptions,
@@ -215,15 +222,17 @@ export async function runFrameworkIdeHotUpdateProbe(
215222
pageUrl,
216223
launchProjectPath,
217224
)
218-
if (!watchCase.skipStyleMutation) {
225+
if (shouldRunIdeStyleHotUpdate(watchCase)) {
219226
await runIdeStyleHotUpdate(
220-
entry,
221227
options,
222228
watchCase,
223229
session,
224230
sourceOriginals.get(watchCase.styleMutation.sourceFile)!,
225231
)
226232
}
233+
else if (!watchCase.skipStyleMutation) {
234+
process.stdout.write(`[e2e:ide] ${watchCase.label} style HMR skipped for IDE stability; watch-HMR keeps style coverage\n`)
235+
}
227236
})(),
228237
)
229238
}

e2e/frameworkIdeStyleHotUpdate.ts

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import type { createWatchSession } from '../tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/session'
22
import type { CliOptions, WatchCase } from '../tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/types'
3-
import type { FrameworkSupportCase } from './frameworkSupportMatrix'
43
import process from 'node:process'
54
import {
5+
createStyleMutationPayload,
66
waitForCompileSettled,
77
waitForOutputFilesUpdated,
88
} from '../tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/mutations'
99
import {
10-
appendTrailingSnippet,
1110
findCssRuleBody,
12-
insertBeforeClosingTag,
1311
normalizeCssDeclaration,
1412
waitFor,
1513
writeFilePreserveEol,
@@ -35,49 +33,39 @@ function getRollbackTimeoutMs(options: CliOptions) {
3533
return Math.min(options.timeoutMs, readNumberEnv('E2E_IDE_ROLLBACK_TIMEOUT_MS', 30_000))
3634
}
3735

38-
function createIdeStyleSnippet(entry: FrameworkSupportCase, marker: string) {
39-
const selector = `.${marker}`
40-
const functionSelector = `.${marker}-theme`
41-
const color = entry.tailwindcss === 'v4' ? '#14532d' : '#1d4ed8'
42-
const lines = [
43-
`${selector} { @apply font-bold text-center bg-[#123456] px-[12px]; color: ${color}; }`,
44-
`${functionSelector} { padding: theme('spacing.2'); margin-left: theme('spacing.3'); }`,
45-
]
46-
if (entry.tailwindcss === 'v4') {
47-
lines.unshift('@reference "tailwindcss";')
48-
}
49-
return lines.join('\n')
50-
}
51-
52-
function mutateStyleSource(source: string, snippet: string) {
53-
if (source.includes('</style>')) {
54-
return insertBeforeClosingTag(source, '</style>', snippet)
55-
}
56-
return appendTrailingSnippet(source, snippet)
57-
}
58-
59-
function assertStyleOutput(watchCase: WatchCase, content: string, marker: string) {
60-
const applyRule = findCssRuleBody(content, `.${marker}`)
36+
function assertStyleOutput(
37+
watchCase: WatchCase,
38+
content: string,
39+
payload: ReturnType<typeof createStyleMutationPayload>,
40+
) {
41+
const applyRule = findCssRuleBody(content, payload.styleNeedle)
6142
if (!applyRule) {
62-
throw new Error(`[${watchCase.label}] IDE style HMR output is missing @apply rule .${marker}`)
43+
throw new Error(`[${watchCase.label}] IDE style HMR output is missing style rule ${payload.styleNeedle}`)
6344
}
6445
const normalizedApplyRule = normalizeCssDeclaration(applyRule)
65-
for (const expected of ['font-weight:', 'text-align:', 'background-color:', 'padding-left:', 'padding-right:']) {
46+
for (const expected of payload.expectedApplyDeclarations) {
6647
if (!normalizedApplyRule.includes(normalizeCssDeclaration(expected))) {
6748
throw new Error(`[${watchCase.label}] IDE style HMR @apply output is missing declaration ${expected}`)
6849
}
6950
}
7051

71-
const functionRule = findCssRuleBody(content, `.${marker}-theme`)
72-
if (!functionRule) {
73-
throw new Error(`[${watchCase.label}] IDE style HMR output is missing Tailwind function rule .${marker}-theme`)
52+
if (!payload.functionNeedle) {
53+
return
7454
}
75-
if (functionRule.includes('theme(')) {
76-
throw new Error(`[${watchCase.label}] IDE style HMR did not resolve Tailwind theme() function`)
55+
56+
const functionRule = findCssRuleBody(content, payload.functionNeedle)
57+
if (!functionRule) {
58+
throw new Error(`[${watchCase.label}] IDE style HMR output is missing Tailwind function rule ${payload.functionNeedle}`)
7759
}
60+
7861
const normalizedFunctionRule = normalizeCssDeclaration(functionRule)
79-
for (const expected of ['padding', 'margin-left']) {
80-
if (!normalizedFunctionRule.includes(`${expected}:`)) {
62+
for (const forbidden of payload.forbiddenFunctionFragments) {
63+
if (functionRule.includes(forbidden)) {
64+
throw new Error(`[${watchCase.label}] IDE style HMR did not resolve Tailwind function fragment ${forbidden}`)
65+
}
66+
}
67+
for (const expected of payload.expectedFunctionDeclarations) {
68+
if (!normalizedFunctionRule.includes(normalizeCssDeclaration(expected))) {
8169
throw new Error(`[${watchCase.label}] IDE style HMR function output is missing declaration ${expected}`)
8270
}
8371
}
@@ -89,16 +77,15 @@ function resolveUpdatedStyleFiles(watchCase: WatchCase, baselineMtimes: Map<stri
8977
}
9078

9179
export async function runIdeStyleHotUpdate(
92-
entry: FrameworkSupportCase,
9380
options: CliOptions,
9481
watchCase: WatchCase,
9582
session: ReturnType<typeof createWatchSession>,
9683
sourceOriginal: string,
9784
) {
9885
const sourceFile = watchCase.styleMutation.sourceFile
9986
process.stdout.write(`[e2e:ide] ${watchCase.label} style HMR mutate ${sourceFile}\n`)
100-
const marker = `tw-ide-style-${watchCase.name}-${Date.now().toString().slice(-6)}`
101-
const mutatedSource = mutateStyleSource(sourceOriginal, createIdeStyleSnippet(entry, marker))
87+
const payload = createStyleMutationPayload(watchCase)
88+
const mutatedSource = watchCase.styleMutation.mutate(sourceOriginal, payload)
10289
const { artifacts: baselineArtifacts, mtimes: baselineMtimes } = await collectArtifactMtimes(watchCase)
10390
const mutationStartedAt = Date.now()
10491

@@ -110,19 +97,19 @@ export async function runIdeStyleHotUpdate(
11097
options,
11198
session,
11299
mutationStartedAt,
113-
async () => hasAnyNeedle(await readArtifacts(watchCase), [marker]),
100+
async () => hasAnyNeedle(await readArtifacts(watchCase), [payload.styleNeedle]),
114101
)
115102

116103
let changedArtifacts: string[] = []
117104
await waitFor(
118105
async () => {
119106
const currentArtifacts = await readArtifacts(watchCase)
120-
const styleArtifacts = currentArtifacts.filter(item => item.kind === 'style' && item.content.includes(marker))
107+
const styleArtifacts = currentArtifacts.filter(item => item.kind === 'style' && item.content.includes(payload.styleNeedle))
121108
if (styleArtifacts.length === 0 || countChangedArtifacts(baselineArtifacts, currentArtifacts) === 0) {
122109
return false
123110
}
124111
for (const artifact of styleArtifacts) {
125-
assertStyleOutput(watchCase, artifact.content, marker)
112+
assertStyleOutput(watchCase, artifact.content, payload)
126113
}
127114
changedArtifacts = summarizeChangedArtifacts(baselineArtifacts, currentArtifacts)
128115
return true
@@ -144,11 +131,11 @@ export async function runIdeStyleHotUpdate(
144131
await writeFilePreserveEol(sourceFile, sourceOriginal, sourceOriginal)
145132
await waitForCompileSettled(watchCase, options, session, rollbackStartedAt)
146133
await waitFor(
147-
async () => !hasAnyNeedle(await readArtifacts(watchCase), [marker]),
134+
async () => !hasAnyNeedle(await readArtifacts(watchCase), [payload.styleNeedle]),
148135
{
149136
timeoutMs: getRollbackTimeoutMs(options),
150137
pollMs: options.pollMs,
151-
message: `[${watchCase.label}] IDE style HMR marker was not removed after rollback: ${marker}`,
138+
message: `[${watchCase.label}] IDE style HMR marker was not removed after rollback: ${payload.styleNeedle}`,
152139
onTick: session.ensureRunning,
153140
},
154141
rollbackStartedAt,

0 commit comments

Comments
 (0)