Skip to content

Commit 3a55c27

Browse files
authored
test(integration): more web-test-runner test fixes @W-18763051 (#5414)
* refactor(wtr): move NODE_ENV_FOR_TEST default into options file * chore(wtr): move hooks util to separate file * chore(wtr): move aria utils to separate file * chore(wtr): move constants to separate file * chore(wtr): clean up custom rollup plugin * test(wtr): get hydration tests kinda running * test(wtr): kinda start moving to ESM instead of IIFE * fix(shared): make sanitizeHtmlContent work * chore(ci): run hydration tests in ci * test(wtr): remove unused script * test(wtr): implement missing jasmine assertions * test(wtr): clean up test to make assertions more clear * test(wtr): implement custom console matchers * test(wtr): use simpler console spy * test(wtr): remove outdated, unnecessary spies * test(wtr): move signals util to own file * test(wtr): implement custom error matchers everything passed first try, which is kinda sus * chore: split matchers into separate files * chore: ugh tui go away * chore: remove unused file code is now in helpers/matchers/index.mjs * test(wtr): conditionally import polyfills reduces test failures from 291 to 220 * test(wtr): use one setup file instead of two * chore: add comment explaining file * chore(wtr): rename file * chore(wtr): move test configs into directory * chore(wtr): extract shared parts of config into base config object * chore(wtr): rename config files who needs convention? * chore(wtr): move WTR plugins from helpers dir to config dir * chore: move full plugins to plugin files instead of just inner logic * test(wtr): not all env vars are boolean fixes ~50 test failures * test(wtr): make tests async so they clean up properly I'm not sure why the async matters, but it does. * test(wtr): fix resolution of wire-service * test(wtr): skip flaky tests * test(wtr): add more jasmine spy adapter methods * test(wtr): enable passing tests turns out they just had browser log warnings, not failures * test(wtr): make spy props non-enumerable * test(wtr): remove unused matcher * test(wtr): fix assertion to match error message * test(wtr): implement jasmine.any * test(wtr): mark test as flaky timeout * update comment * update comment * test(wtr): move scripts to head instead of body tests manipulate the body, so we use head for scripts to keep the body clean * Update packages/@lwc/integration-not-karma/configs/base.mjs * Update packages/@lwc/integration-not-karma/configs/base.mjs
1 parent e02e9d8 commit 3a55c27

File tree

13 files changed

+176
-290
lines changed

13 files changed

+176
-290
lines changed

packages/@lwc/integration-karma/test/api/getComponentDef/index.spec.js

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,6 @@ function testInvalidComponentConstructor(name, ctor) {
1717
});
1818
}
1919

20-
beforeAll(function () {
21-
const getNormalizedFunctionAsString = (fn) => fn.toString().replace(/(\s|\n)/g, '');
22-
23-
jasmine.addMatchers({
24-
toEqualWireSettings: function () {
25-
return {
26-
compare: function (actual, expected) {
27-
Object.keys(actual).forEach((currentKey) => {
28-
const normalizedActual = Object.assign({}, actual[currentKey], {
29-
config: getNormalizedFunctionAsString(actual[currentKey].config),
30-
});
31-
32-
const normalizedExpected = Object.assign({}, expected[currentKey], {
33-
config: getNormalizedFunctionAsString(
34-
expected[currentKey].config || function () {}
35-
),
36-
});
37-
38-
expect(normalizedActual).toEqual(normalizedExpected);
39-
});
40-
41-
return {
42-
pass: true,
43-
};
44-
},
45-
};
46-
},
47-
});
48-
});
49-
5020
testInvalidComponentConstructor('null', null);
5121
testInvalidComponentConstructor('undefined', undefined);
5222
testInvalidComponentConstructor('String', 'component');

packages/@lwc/integration-karma/test/component/native-vs-synthetic-lifecycle/index.spec.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ const expectLogs = (regexes) => {
2525
const args = logger.calls.allArgs();
2626
expect(args.length).toBe(regexes.length);
2727
for (let i = 0; i < args.length; i++) {
28-
expect(args[i][0]).toMatch(regexes[i]);
28+
expect(args[i][0]).toBeInstanceOf(Error);
29+
expect(args[i][0].message).toMatch(regexes[i]);
2930
}
3031
}
3132
};

packages/@lwc/integration-karma/test/wire/wiring/index.spec.js

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function filterCalls(echoAdapterSpy, methodType) {
2121

2222
describe('wiring', () => {
2323
describe('component lifecycle and wire adapter', () => {
24-
it('should call a connect when component is connected', () => {
24+
it('should call a connect when component is connected', async () => {
2525
const spy = [];
2626
const elm = createElement('x-echo-adapter-consumer', { is: ComponentClass });
2727
AdapterId.setSpy(spy);
@@ -30,7 +30,7 @@ describe('wiring', () => {
3030
expect(filterCalls(spy, 'connect').length).toBe(1);
3131
});
3232

33-
it('should call a disconnect when component is disconnected', () => {
33+
it('should call a disconnect when component is disconnected', async () => {
3434
const spy = [];
3535
AdapterId.setSpy(spy);
3636
const elm = createElement('x-echo-adapter-consumer', { is: ComponentClass });
@@ -40,7 +40,7 @@ describe('wiring', () => {
4040
expect(filterCalls(spy, 'disconnect').length).toBe(1);
4141
});
4242

43-
it('should call a connect and disconnect when component is connected, disconnected twice', () => {
43+
it('should call a connect and disconnect when component is connected, disconnected twice', async () => {
4444
const spy = [];
4545
const elm = createElement('x-echo-adapter-consumer', { is: ComponentClass });
4646
AdapterId.setSpy(spy);
@@ -59,7 +59,7 @@ describe('wiring', () => {
5959
});
6060

6161
describe('update method on wire adapter', () => {
62-
it('should be called in same tick when component with wire no dynamic params is created', () => {
62+
it('should be called in same tick when component with wire no dynamic params is created', async () => {
6363
const spy = [];
6464
AdapterId.setSpy(spy);
6565
expect(spy.length).toBe(0);
@@ -83,7 +83,7 @@ describe('wiring', () => {
8383
setFeatureFlagForTest('ENABLE_WIRE_SYNC_EMIT', false);
8484
});
8585

86-
it('should be called synchronously after connect when a component with wire that has dynamic params is created', () => {
86+
it('should be called synchronously after connect when a component with wire that has dynamic params is created', async () => {
8787
const spy = [];
8888
AdapterId.setSpy(spy);
8989
expect(spy.length).toBe(0);
@@ -96,7 +96,7 @@ describe('wiring', () => {
9696
expect(spy[1].method).toBe('update');
9797
});
9898

99-
it('should call synchronously update only once when the component is created and a wire dynamic param is modified', () => {
99+
it('should call synchronously update only once when the component is created and a wire dynamic param is modified', async () => {
100100
const spy = [];
101101
AdapterId.setSpy(spy);
102102
expect(spy.length).toBe(0);
@@ -112,7 +112,7 @@ describe('wiring', () => {
112112
});
113113
});
114114

115-
it('should be called next tick when the component with wire that has dynamic params is created', () => {
115+
it('should be called next tick when the component with wire that has dynamic params is created', async () => {
116116
const spy = [];
117117
AdapterId.setSpy(spy);
118118
expect(spy.length).toBe(0);
@@ -130,7 +130,7 @@ describe('wiring', () => {
130130
});
131131
});
132132

133-
it('should call update only once when the component is created and a wire dynamic param is modified in the same tick', () => {
133+
it('should call update only once when the component is created and a wire dynamic param is modified in the same tick', async () => {
134134
const spy = [];
135135
AdapterId.setSpy(spy);
136136
expect(spy.length).toBe(0);
@@ -147,7 +147,7 @@ describe('wiring', () => {
147147
});
148148
});
149149

150-
it('should be called only once during multiple renders when the wire config does not change', () => {
150+
it('should be called only once during multiple renders when the wire config does not change', async () => {
151151
const spy = [];
152152
AdapterId.setSpy(spy);
153153
const elm = createElement('x-echo-adapter-consumer', { is: ComponentClass });
@@ -165,7 +165,7 @@ describe('wiring', () => {
165165
});
166166
});
167167

168-
it('should be called when the wire parameters change its value.', () => {
168+
it('should be called when the wire parameters change its value.', async () => {
169169
const spy = [];
170170
AdapterId.setSpy(spy);
171171
const elm = createElement('x-echo-adapter-consumer', { is: ComponentClass });
@@ -186,7 +186,7 @@ describe('wiring', () => {
186186
});
187187
});
188188

189-
it('should be called for common parameter when shared among wires', () => {
189+
it('should be called for common parameter when shared among wires', async () => {
190190
const spy = [];
191191
AdapterId.setSpy(spy);
192192
const elm = createElement('x-bc-consumer', { is: BroadcastConsumer });
@@ -209,7 +209,7 @@ describe('wiring', () => {
209209
});
210210
});
211211

212-
it('should not update when setting parameter with same value', () => {
212+
it('should not update when setting parameter with same value', async () => {
213213
const spy = [];
214214
const elm = createElement('x-echo-adapter-consumer', { is: ComponentClass });
215215
document.body.appendChild(elm);
@@ -255,7 +255,7 @@ describe('wiring', () => {
255255
expect(dynamicValue.textContent).toBe('modified value');
256256
});
257257

258-
it('should not call update when component is disconnected.', () => {
258+
it('should not call update when component is disconnected.', async () => {
259259
const spy = [];
260260
AdapterId.setSpy(spy);
261261
const elm = createElement('x-echo-adapter-consumer', { is: ComponentClass });
@@ -272,7 +272,7 @@ describe('wiring', () => {
272272
});
273273
});
274274

275-
it('should call update when component is re-connected.', () => {
275+
it('should call update when component is re-connected.', async () => {
276276
const spy = [];
277277
AdapterId.setSpy(spy);
278278
const elm = createElement('x-echo-adapter-consumer', { is: ComponentClass });
@@ -302,7 +302,7 @@ describe('wiring', () => {
302302
});
303303

304304
describe('wired fields', () => {
305-
it('should rerender component when adapter pushes data', () => {
305+
it('should rerender component when adapter pushes data', async () => {
306306
BroadcastAdapter.clearInstances();
307307
const elm = createElement('x-bc-consumer', { is: BroadcastConsumer });
308308
document.body.appendChild(elm);
@@ -322,7 +322,7 @@ describe('wired fields', () => {
322322
});
323323
});
324324

325-
it('should rerender component when wired field is mutated from within the component', () => {
325+
it('should rerender component when wired field is mutated from within the component', async () => {
326326
BroadcastAdapter.clearInstances();
327327
const elm = createElement('x-bc-consumer', { is: BroadcastConsumer });
328328
document.body.appendChild(elm);
@@ -343,7 +343,7 @@ describe('wired fields', () => {
343343
});
344344

345345
describe('wired methods', () => {
346-
it('should call component method when wired to a method', () => {
346+
it('should call component method when wired to a method', async () => {
347347
BroadcastAdapter.clearInstances();
348348
const elm = createElement('x-bc-consumer', { is: BroadcastConsumer });
349349
document.body.appendChild(elm);
@@ -355,7 +355,7 @@ describe('wired methods', () => {
355355
});
356356
});
357357

358-
it('should support method override', () => {
358+
it('should support method override', async () => {
359359
const spy = [];
360360
EchoWireAdapter.setSpy(spy);
361361
const elm = createElement('x-inherited-methods', { is: InheritedMethods });
@@ -376,7 +376,7 @@ describe('wired methods', () => {
376376
});
377377

378378
describe('context aware', () => {
379-
it('should receive the source element tag name when adapter is constructed', () => {
379+
it('should receive the source element tag name when adapter is constructed', async () => {
380380
const spy = [];
381381
ContextLog.setSpy(spy);
382382

Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import { join } from 'node:path';
12
import { LWC_VERSION } from '@lwc/shared';
2-
import * as options from './helpers/options.mjs';
3-
import wrapHydrationTest from './helpers/hydration-tests.mjs';
3+
import * as options from '../helpers/options.mjs';
44

5-
const pluck = (obj, keys) => Object.fromEntries(keys.map((k) => [k, Boolean(obj[k])]));
5+
const pluck = (obj, keys) => Object.fromEntries(keys.map((k) => [k, obj[k]]));
6+
const maybeImport = (file, condition) => (condition ? `await import('${file}');` : '');
67

78
/** `process.env` to inject into test environment. */
89
const env = {
@@ -20,32 +21,21 @@ const env = {
2021
LWC_VERSION,
2122
NODE_ENV: options.NODE_ENV_FOR_TEST,
2223
};
24+
2325
/** @type {import("@web/test-runner").TestRunnerConfig} */
2426
export default {
25-
files: [
26-
// FIXME: These tests are just symlinks to integration-karma for now so the git diff smaller
27-
'test-hydration/**/*.spec.js',
28-
'!test-hydration/light-dom/scoped-styles/replace-scoped-styles-with-dynamic-templates/index.spec.js',
29-
],
3027
nodeResolve: true,
31-
rootDir: import.meta.dirname,
28+
rootDir: join(import.meta.dirname, '..'),
3229
plugins: [
3330
{
3431
resolveImport({ source }) {
3532
if (source === 'test-utils') {
36-
return '/helpers/wtr-utils.mjs';
33+
return '/helpers/utils.mjs';
3734
} else if (source === 'wire-service') {
38-
return '@lwc/wire-service';
39-
}
40-
},
41-
async serve(ctx) {
42-
// Hydration test "index.spec.js" files are actually just config files.
43-
// They don't directly define the tests. Instead, when we request the file,
44-
// we wrap it with some boilerplate. That boilerplate must include the config
45-
// file we originally requested, so the ?original query parameter is used
46-
// to return the file unmodified.
47-
if (ctx.path.endsWith('.spec.js') && !ctx.query.original) {
48-
return await wrapHydrationTest(ctx.path.slice(1)); // remove leading /
35+
// To serve files outside the web root (e.g. node_modules in the monorepo root),
36+
// @web/dev-server provides this "magic" path. It's hacky of us to use it directly.
37+
// `/__wds-outside-root__/${depth}/` === '../'.repeat(depth)
38+
return '/__wds-outside-root__/1/wire-service/dist/index.js';
4939
}
5040
},
5141
async transform(ctx) {
@@ -59,16 +49,19 @@ export default {
5949
testRunnerHtml: (testFramework) =>
6050
`<!DOCTYPE html>
6151
<html>
62-
<body>
52+
<head>
53+
<!-- scripts are included in the head so that the body can be fully reset between tests -->
6354
<script type="module">
6455
globalThis.process = ${JSON.stringify({ env })};
6556
globalThis.lwcRuntimeFlags = ${JSON.stringify(
6657
pluck(options, ['DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE'])
6758
)};
59+
60+
${maybeImport('@lwc/synthetic-shadow', !options.DISABLE_SYNTHETIC)}
61+
${maybeImport('@lwc/aria-reflection', options.ENABLE_ARIA_REFLECTION_GLOBAL_POLYFILL)}
6862
</script>
6963
<script type="module" src="./helpers/setup.mjs"></script>
70-
<script type="module" src="./helpers/wtr-utils.mjs"></script>
7164
<script type="module" src="${testFramework}"></script>
72-
</body>
65+
</head>
7366
</html>`,
7467
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Use native shadow by default in hydration tests; MUST be set before imports
2+
process.env.DISABLE_SYNTHETIC ??= 'true';
3+
import baseConfig from './base.mjs';
4+
import hydrationTestPlugin from './plugins/serve-hydration.mjs';
5+
6+
/** @type {import("@web/test-runner").TestRunnerConfig} */
7+
export default {
8+
...baseConfig,
9+
files: [
10+
// FIXME: These tests are just symlinks to integration-karma for now so the git diff smaller
11+
'test-hydration/**/*.spec.js',
12+
// FIXME: hits timeout?
13+
'!test-hydration/light-dom/scoped-styles/replace-scoped-styles-with-dynamic-templates/index.spec.js',
14+
// FIXME: This uses ENABLE_SYNTHETIC_SHADOW_IN_MIGRATION to detect status,
15+
// we should just use DISABLE_SYNTHETIC instead
16+
'!test-hydration/synthetic-shadow/index.spec.js',
17+
],
18+
plugins: [...baseConfig.plugins, hydrationTestPlugin],
19+
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import baseConfig from './base.mjs';
2+
import testPlugin from './plugins/serve-integration.mjs';
3+
4+
/** @type {import("@web/test-runner").TestRunnerConfig} */
5+
export default {
6+
...baseConfig,
7+
files: [
8+
// FIXME: These tests are just symlinks to integration-karma for now so the git diff smaller
9+
'test/**/*.spec.js',
10+
'!test/events/focus-event-related-target/index.spec.js',
11+
'!test/light-dom/multiple-templates/index.spec.js',
12+
'!test/light-dom/scoped-slot/if-block/index.spec.js',
13+
'!test/light-dom/scoped-styles/index.spec.js',
14+
'!test/light-dom/style-global/index.spec.js',
15+
'!test/misc/clean-dom/index.spec.js',
16+
'!test/polyfills/document-body-properties/index.spec.js',
17+
'!test/polyfills/document-properties/index.spec.js',
18+
'!test/profiler/mutation-logging/index.spec.js',
19+
'!test/regression/invalid-key/index.spec.js',
20+
'!test/rendering/iframe/index.spec.js',
21+
'!test/rendering/inner-outer-html/index.spec.js',
22+
'!test/rendering/legacy-stylesheet-api/index.spec.js',
23+
'!test/rendering/sanitize-stylesheet-token/index.spec.js',
24+
'!test/rendering/slotting/index.spec.js',
25+
'!test/rendering/stylesheet-caching/index.spec.js',
26+
'!test/shadow-dom/ShadowRoot.elementsFromPoint/index.spec.js',
27+
'!test/signal/protocol/index.spec.js',
28+
'!test/spread/index.spec.js',
29+
'!test/swapping/styles/index.spec.js',
30+
'!test/template/directive-for-each/index.spec.js',
31+
32+
// Flaky tests that sometimes time out
33+
'!test/light-dom/host-pseudo/index.spec.js',
34+
'!test/rendering/programmatic-stylesheets/index.spec.js',
35+
'!test/shadow-dom/multiple-templates/index.spec.js',
36+
'!test/synthetic-shadow/dom-manual-sharing-nodes/index.spec.js',
37+
'!test/synthetic-shadow/host-pseudo/index.spec.js',
38+
'!test/synthetic-shadow/style-svg/index.spec.js',
39+
40+
// Cannot reassign properties of module
41+
'!test/api/sanitizeAttribute/index.spec.js',
42+
43+
// Hacky nonsense highly tailored to Karma
44+
'!test/custom-elements-registry/index.spec.js',
45+
46+
// Logging mismatches
47+
'!test/accessibility/synthetic-cross-root-aria/index.spec.js',
48+
'!test/api/freezeTemplate/index.spec.js',
49+
'!test/component/LightningElement.addEventListener/index.spec.js',
50+
],
51+
plugins: [...baseConfig.plugins, testPlugin],
52+
};

0 commit comments

Comments
 (0)