Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type { Stylesheet } from '@lwc/shared';
let warned = false;

// Only used in LWC's Karma tests
if (process.env.NODE_ENV === 'test-karma-lwc') {
if (process.env.NODE_ENV === 'test-lwc-integration') {
(window as any).__lwcResetWarnedOnVersionMismatch = () => {
warned = false;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const fragmentCache: WeakMap<string[], Element>[] = ArrayFrom(
);

// Only used in LWC's Karma tests
if (process.env.NODE_ENV === 'test-karma-lwc') {
if (process.env.NODE_ENV === 'test-lwc-integration') {
(window as any).__lwcResetFragmentCache = () => {
for (let i = 0; i < fragmentCache.length; i++) {
fragmentCache[i] = new WeakMap();
Expand Down
2 changes: 1 addition & 1 deletion packages/@lwc/engine-core/src/framework/hot-swaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ let activeComponents: WeakMultiMap<LightningElementConstructor, VM> =
let activeStyles: WeakMultiMap<Stylesheet, VM> = /*@__PURE__@*/ new WeakMultiMap();

// Only used in LWC's Karma tests
if (process.env.NODE_ENV === 'test-karma-lwc') {
if (process.env.NODE_ENV === 'test-lwc-integration') {
// Used to reset the global state between test runs
(window as any).__lwcResetHotSwaps = () => {
swappedTemplateMap = new WeakMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export function logMutation(reactiveObserver: ReactiveObserver, target: object,
// because the unit tests just create Reactive Observers on-the-fly.
// Note we could explicitly target Vitest with `process.env.NODE_ENV === 'test'`, but then that would also
// affect our downstream consumers' Jest/Vitest tests, and we don't want to throw an error just for a logger.
if (process.env.NODE_ENV === 'test-karma-lwc') {
if (process.env.NODE_ENV === 'test-lwc-integration') {
throw new Error('The VM should always be defined except possibly in unit tests');
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion packages/@lwc/engine-core/src/framework/stylesheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ let stylesheetsToCssContent: WeakMap<Stylesheet, Set<string>> = /*@__PURE__@*/ n
let cssContentToAbortControllers: Map<string, AbortController> = /*@__PURE__@*/ new Map();

// Only used in LWC's Karma tests
if (process.env.NODE_ENV === 'test-karma-lwc') {
if (process.env.NODE_ENV === 'test-lwc-integration') {
// Used to reset the global state between test runs
(window as any).__lwcResetStylesheetCache = () => {
stylesheetsToCssContent = new WeakMap();
Expand Down
2 changes: 1 addition & 1 deletion packages/@lwc/engine-core/src/framework/vm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ function computeShadowMode(
if (
// Force the shadow mode to always be native. Used for running tests with synthetic shadow patches
// on, but components running in actual native shadow mode
(process.env.NODE_ENV === 'test-karma-lwc' &&
(process.env.NODE_ENV === 'test-lwc-integration' &&
process.env.FORCE_NATIVE_SHADOW_MODE_FOR_TEST) ||
// If synthetic shadow is explicitly disabled, use pure-native
lwcRuntimeFlags.DISABLE_SYNTHETIC_SHADOW ||
Expand Down
2 changes: 1 addition & 1 deletion packages/@lwc/engine-core/src/shared/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { VM } from '../framework/vm';
const alreadyLoggedMessages = new Set();

// Only used in LWC's Karma tests
if (process.env.NODE_ENV === 'test-karma-lwc') {
if (process.env.NODE_ENV === 'test-lwc-integration') {
(window as any).__lwcResetAlreadyLoggedMessages = () => {
alreadyLoggedMessages.clear();
};
Expand Down
2 changes: 1 addition & 1 deletion packages/@lwc/engine-dom/src/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const stylesheetCache: Map<string, CacheData> = new Map();
//

// Only used in LWC's Karma tests
if (process.env.NODE_ENV === 'test-karma-lwc') {
if (process.env.NODE_ENV === 'test-lwc-integration') {
(window as any).__lwcResetGlobalStylesheets = () => {
stylesheetCache.clear();
};
Expand Down
8 changes: 4 additions & 4 deletions packages/@lwc/features/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ export function setFeatureFlag(name: FeatureFlagName, value: FeatureFlagValue):
);
return;
}
// This may seem redundant, but `process.env.NODE_ENV === 'test-karma-lwc'` is replaced by Karma tests
if (process.env.NODE_ENV === 'test-karma-lwc' || process.env.NODE_ENV !== 'production') {
// This may seem redundant, but `process.env.NODE_ENV === 'test-lwc-integration'` is replaced by Karma tests
if (process.env.NODE_ENV === 'test-lwc-integration' || process.env.NODE_ENV !== 'production') {
// Allow the same flag to be set more than once outside of production to enable testing
flags[name] = value;
} else {
Expand All @@ -86,8 +86,8 @@ export function setFeatureFlag(name: FeatureFlagName, value: FeatureFlagValue):
* @example setFeatureFlag("DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE", true)
*/
export function setFeatureFlagForTest(name: FeatureFlagName, value: FeatureFlagValue): void {
// This may seem redundant, but `process.env.NODE_ENV === 'test-karma-lwc'` is replaced by Karma tests
if (process.env.NODE_ENV === 'test-karma-lwc' || process.env.NODE_ENV !== 'production') {
// This may seem redundant, but `process.env.NODE_ENV === 'test-lwc-integration'` is replaced by Karma tests
if (process.env.NODE_ENV === 'test-lwc-integration' || process.env.NODE_ENV !== 'production') {
setFeatureFlag(name, value);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,10 @@ function createHCONFIG2JSPreprocessor(config, logger, emitter) {
testWatchFiles.concat(componentWatchFilesCSR).concat(componentWatchFilesSSR)
);
ssrOutput = await getSsrCode(
componentDefSSR.replace(`process.env.NODE_ENV === 'test-karma-lwc'`, 'true'),
componentDefSSR.replace(
`process.env.NODE_ENV === 'test-lwc-integration'`,
'true'
),
testCode,
path.join(suiteDir, 'ssr.js'),
expectedSSRConsoleCalls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ function createPreprocessor(config, emitter, logger) {
const magicString = new MagicString(content.replace(/\/\/# sourceMappingURL=\S+/, ''));

/**
* This transformation replaces `process.env.NODE_ENV === 'test-karma-lwc'` with `true`.
* This transformation replaces `process.env.NODE_ENV === 'test-lwc-integration'` with `true`.
*
* You might wonder why we replace the whole thing rather than just `process.env.NODE_ENV`. Well, because we need a way
* to test `process.env.NODE_ENV === "production"` (prod mode) vs `process.env.NODE_ENV !== "production"` (dev mode).
* If we replaced `process.env.NODE_ENV`, then that would be impossible.
*
* Then you might wonder why we call it "test-karma-lwc" rather than something simple like "test". Well, because
* Then you might wonder why we call it "test-lwc-integration" rather than something simple like "test". Well, because
* "test" was already squatted by Jest, and we actually use it for Jest-specific (not Karma-specific) behavior:
* - https://jestjs.io/docs/environment-variables#node_env
* - https://github.com/search?q=repo%3Asalesforce%2Flwc%20node_env%20%3D%3D%3D%20%27test%27&type=code
Expand All @@ -71,7 +71,7 @@ function createPreprocessor(config, emitter, logger) {
*
* So that's why this is so weird and complicated. I'm sorry.
*/
const replacee = `process.env.NODE_ENV === 'test-karma-lwc'`;
const replacee = `process.env.NODE_ENV === 'test-lwc-integration'`;
// pad to keep things pretty in Istanbul coverage HTML
magicString.replaceAll(replacee, 'true'.padEnd(replacee.length, ' '));

Expand Down
2 changes: 1 addition & 1 deletion packages/@lwc/integration-not-karma/configs/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default (options) => {
if (ctx.type === 'application/javascript') {
// FIXME: copy/paste Nolan's spiel about why we do this ugly thing
return ctx.body.replace(
/process\.env\.NODE_ENV === 'test-karma-lwc'/g,
/process\.env\.NODE_ENV === 'test-lwc-integration'/g,
'true'
);
}
Expand Down
82 changes: 82 additions & 0 deletions packages/@lwc/integration-not-karma/helpers/reset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* @fileoverview There are a number of __lwcReset functions scattered throughout
* the LWC codebase that are only defined when running integration tests, which
* reset various global states used by the framework. When updating tests, it is
* not always obvious to new developers where each function is defined and what
* purpose it serves. This file is intended to consolidate the functions, in
* order to reduce the amout of "magic" in the code.
*/

function clearElement(elm) {
// `childNodes` and `attributes` are live lists, so we clone them to avoid
// skipping values as we delete items in the list
for (const child of [...elm.childNodes]) {
// Synthetic custom element lifecycle only patches DOM manipulation
// methods on Node.prototype, not Element.prototype, so we must use Node
// methods for signals tests to pass when using synthetic lifecycle.
elm.removeChild(child);
}
expect(elm.hasChildNodes(), `${elm.outerHTML} should not have child nodes`).toBe(false);

for (const attr of [...elm.attributes]) {
elm.removeAttributeNode(attr);
}
expect(elm.attributes, `${elm.outerHTML} should not have attributes`).toHaveSize(0);
}

/**
* Clears all nodes from the document's `head` and `body` and resets LWC's
* stylesheets cache.
* @see engine-dom/src/styles.ts
*/
export function resetDOM() {
clearElement(document.body);
clearElement(document.head);

// LWC caches stylesheet data; we need to reset the cache when we clear the
// DOM, otherwise components will render with incorrect styles
// Defined in engine-dom/src/styles.ts
globalThis.__lwcResetGlobalStylesheets();
}

/**
* Resets the tracker for messages that only get logged once.
* @see engine-core/src/shared/logger.ts
*/
export function resetAlreadyLoggedMessages() {
globalThis.__lwcResetAlreadyLoggedMessages();
}

/**
* Resets the global state used for managing hot swaps.
* @see engine-core/src/framework/hot-swaps.ts
* @see engine-core/src/framework/stylehseet.ts
*/
export function resetHotSwaps() {
globalThis.__lwcResetHotSwaps();
globalThis.__lwcResetStylesheetCache();
}

/**
* Resets the tracker for "trusted" signals, reverting to "untrusted" mode.
* @see shared/src/signals.ts
*/
export function resetTrustedSignals() {
globalThis.__lwcResetTrustedSignals();
}

/**
* Resets the fragment cache. TBH, I don't know what that is.
* @see engine-core/src/framework/fragment-cache.ts
*/
export function resetFragmentCache() {
return globalThis.__lwcResetFragmentCache();
}

/**
* The warning is supposed to only be logged once. This resets that tracker.
* @see engine-core/src/framework/check-version-mismatch.ts
*/
export function resetWarnedOnVersionMismatch() {
return globalThis.__lwcResetWarnedOnVersionMismatch();
}
16 changes: 0 additions & 16 deletions packages/@lwc/integration-not-karma/helpers/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,3 @@ hijackGlobal('after', (after) => {
// Expose as an alias for migration
globalThis.afterAll = after;
});

hijackGlobal('afterEach', (afterEach) => {
afterEach(() => {
// FIXME: Boost test speed by moving this to only files that need it
// Ensure the DOM is in a clean state
document.body.replaceChildren();
document.head.replaceChildren();
});
});

hijackGlobal('beforeEach', (beforeEach) => {
beforeEach(() => {
// FIXME: Boost test speed by moving this to only files that need it
window.__lwcResetAlreadyLoggedMessages();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
attachReportingControlDispatcher,
detachReportingControlDispatcher,
} from '../../../helpers/reporting-control.js';
import { resetAlreadyLoggedMessages } from '../../../helpers/reset.js';

// This test only works if the ARIA reflection polyfill is loaded
describe.runIf(process.env.ENABLE_ARIA_REFLECTION_GLOBAL_POLYFILL)(
Expand All @@ -21,6 +22,7 @@ describe.runIf(process.env.ENABLE_ARIA_REFLECTION_GLOBAL_POLYFILL)(

afterEach(() => {
detachReportingControlDispatcher();
resetAlreadyLoggedMessages();
});

nonStandardAriaProperties.forEach((prop) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
attachReportingControlDispatcher,
detachReportingControlDispatcher,
} from '../../../helpers/reporting-control.js';
import { resetAlreadyLoggedMessages, resetDOM } from '../../../helpers/reset.js';

const expectedMessageForCrossRoot =
'Error: [LWC warn]: Element <input> uses attribute "aria-labelledby" to reference element <label>, which is not in the same shadow root. This will break in native shadow DOM. For details, see: https://sfdc.co/synthetic-aria\n<x-aria-source>';
Expand All @@ -31,6 +32,8 @@ describe.skipIf(process.env.NATIVE_SHADOW)('synthetic shadow cross-root ARIA', (

afterEach(() => {
detachReportingControlDispatcher();
resetAlreadyLoggedMessages();
resetDOM();
});

describe('detection', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
attachReportingControlDispatcher,
detachReportingControlDispatcher,
} from '../../../helpers/reporting-control.js';
import { resetAlreadyLoggedMessages } from '../../../helpers/reset.js';

describe('freezeTemplate', () => {
let dispatcher;
Expand All @@ -16,6 +17,7 @@ describe('freezeTemplate', () => {

afterEach(() => {
detachReportingControlDispatcher();
resetAlreadyLoggedMessages();
});

it('should warn when setting tmpl.stylesheetToken', () => {
Expand Down Expand Up @@ -112,7 +114,7 @@ describe('freezeTemplate', () => {
/Mutating the "stylesheets" property on a template is deprecated and will be removed in a future version of LWC/
);

window.__lwcResetAlreadyLoggedMessages();
resetAlreadyLoggedMessages();

expect(template.stylesheets.length).toEqual(2);
expect(template.stylesheets[0]).toBe(stylesheet);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import { createElement } from 'lwc';

import Multi from 'x/multi';
import MultiNoStyleInFirst from 'x/multiNoStyleInFirst';
import { resetDOM } from '../../../helpers/reset';

describe('multiple templates', () => {
afterEach(resetDOM);

it('can render multiple templates with different styles', async () => {
const element = createElement('x-multi', { is: Multi });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import { createElement, setFeatureFlagForTest } from 'lwc';
import Container from 'x/container';
import Two from 'x/two';
import Shadow from 'x/shadow';
import { resetDOM } from '../../../helpers/reset';

describe('Light DOM styling at the global level', () => {
afterEach(resetDOM);

it('styles bleed into other light DOM but not shadow DOM components in root context', () => {
const elm = createElement('x-container', { is: Container });
document.body.appendChild(elm);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ import GrandparentResetParentAnyChildReset from 'x/grandparentResetParentAnyChil
import GrandparentResetParentResetChildAny from 'x/grandparentResetParentResetChildAny';
import GrandparentResetParentResetChildReset from 'x/grandparentResetParentResetChildReset';
import { extractDataIds, isNativeShadowRootInstance } from '../../../helpers/utils.js';
import { resetDOM } from '../../../helpers/reset.js';

afterEach(() => {
window.__lwcResetGlobalStylesheets();
});
afterEach(resetDOM);

describe.skipIf(process.env.NATIVE_SHADOW)('synthetic behavior', () => {
const scenarios = [
Expand Down
Loading