Skip to content

Commit

Permalink
refactor: organize API versioning tests (#4040)
Browse files Browse the repository at this point in the history
  • Loading branch information
nolanlawson authored Mar 8, 2024
1 parent 21b57fe commit ccd0253
Show file tree
Hide file tree
Showing 28 changed files with 136 additions and 126 deletions.
66 changes: 32 additions & 34 deletions packages/@lwc/integration-karma/helpers/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,16 +315,14 @@ window.TestUtils = (function (lwc, jasmine, beforeAll) {
return error;
}

var nativeCustomElementLifecycleEnabled = process.env.API_VERSION >= 61;

// For errors we expect to be thrown in the connectedCallback() phase
// of a custom element, there are two possibilities:
// 1) We're using non-native lifecycle callbacks, so the error is thrown synchronously
// 2) We're using native lifecycle callbacks, so the error is thrown asynchronously and can
// only be caught with window.addEventListener('error')
// - Note native lifecycle callbacks are all thrown asynchronously.
function customElementCallbackReactionErrorListener(callback) {
return nativeCustomElementLifecycleEnabled
return apiFeatures.ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE
? windowErrorListener(callback)
: directErrorListener(callback);
}
Expand Down Expand Up @@ -548,12 +546,7 @@ window.TestUtils = (function (lwc, jasmine, beforeAll) {
];

const ariaProperties = Object.keys(ariaPropertiesMapping);

// Can't use Object.values because we need to support IE11
const ariaAttributes = [];
for (let i = 0; i < ariaProperties.length; i++) {
ariaAttributes.push(ariaPropertiesMapping[ariaProperties[i]]);
}
const ariaAttributes = Object.values(ariaPropertiesMapping);

// Keep traversing up the prototype chain until a property descriptor is found
function getPropertyDescriptor(object, prop) {
Expand All @@ -567,32 +560,37 @@ window.TestUtils = (function (lwc, jasmine, beforeAll) {
}

// These values are based on the API versions in @lwc/shared/api-version
const lightDomSlotForwardingEnabled = process.env.API_VERSION > 60;
const vFragBookEndEnabled = process.env.API_VERSION > 59;
const apiFeatures = {
LOWERCASE_SCOPE_TOKENS: process.env.API_VERSION >= 59,
USE_COMMENTS_FOR_FRAGMENT_BOOKENDS: process.env.API_VERSION >= 60,
USE_FRAGMENTS_FOR_LIGHT_DOM_SLOTS: process.env.API_VERSION >= 60,
DISABLE_OBJECT_REST_SPREAD_TRANSFORMATION: process.env.API_VERSION >= 60,
ENABLE_ELEMENT_INTERNALS: process.env.API_VERSION >= 61,
ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE: process.env.API_VERSION >= 61,
USE_LIGHT_DOM_SLOT_FORWARDING: process.env.API_VERSION >= 61,
};

return {
clearRegister: clearRegister,
extractDataIds: extractDataIds,
extractShadowDataIds: extractShadowDataIds,
getHostChildNodes: getHostChildNodes,
isNativeShadowRootInstance: isNativeShadowRootInstance,
isSyntheticShadowRootInstance: isSyntheticShadowRootInstance,
load: load,
registerForLoad: registerForLoad,
getHooks: getHooks,
setHooks: setHooks,
spyConsole: spyConsole,
customElementCallbackReactionErrorListener: customElementCallbackReactionErrorListener,
ariaPropertiesMapping: ariaPropertiesMapping,
ariaProperties: ariaProperties,
ariaAttributes: ariaAttributes,
nonStandardAriaProperties: nonStandardAriaProperties,
nonPolyfilledAriaProperties: nonPolyfilledAriaProperties,
getPropertyDescriptor: getPropertyDescriptor,
attachReportingControlDispatcher: attachReportingControlDispatcher,
detachReportingControlDispatcher: detachReportingControlDispatcher,
nativeCustomElementLifecycleEnabled: nativeCustomElementLifecycleEnabled,
lightDomSlotForwardingEnabled: lightDomSlotForwardingEnabled,
vFragBookEndEnabled: vFragBookEndEnabled,
clearRegister,
extractDataIds,
extractShadowDataIds,
getHostChildNodes,
isNativeShadowRootInstance,
isSyntheticShadowRootInstance,
load,
registerForLoad,
getHooks,
setHooks,
spyConsole,
customElementCallbackReactionErrorListener,
ariaPropertiesMapping,
ariaProperties,
ariaAttributes,
nonStandardAriaProperties,
nonPolyfilledAriaProperties,
getPropertyDescriptor,
attachReportingControlDispatcher,
detachReportingControlDispatcher,
...apiFeatures,
};
})(LWC, jasmine, beforeAll);
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LightningElement } from 'lwc';
import { vFragBookEndEnabled } from 'test-utils';
import { USE_COMMENTS_FOR_FRAGMENT_BOOKENDS } from 'test-utils';

import ReflectElement from 'x/reflect';
import LifecycleParent from 'x/lifecycleParent';
Expand All @@ -11,7 +11,7 @@ import ReflectCamel from 'x/reflectCamel';
import WithChildElmsHasSlot from 'x/withChildElmsHasSlot';
import WithChildElmsHasSlotLight from 'x/withChildElmsHasSlotLight';

const vFragBookend = vFragBookEndEnabled ? '<!---->' : '';
const vFragBookend = USE_COMMENTS_FOR_FRAGMENT_BOOKENDS ? '<!---->' : '';

it('should throw when trying to claim abstract LightningElement as custom element', () => {
expect(() => LightningElement.CustomElementConstructor).toThrowError(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createElement } from 'lwc';
import { customElementCallbackReactionErrorListener } from 'test-utils';
import { customElementCallbackReactionErrorListener, ENABLE_ELEMENT_INTERNALS } from 'test-utils';

import ShadowDomCmp from 'ai/shadowDom';
import LightDomCmp from 'ai/lightDom';
Expand Down Expand Up @@ -54,7 +54,7 @@ const attachInternalsSanityTest = (tagName, ctor) => {
});
};

if (process.env.API_VERSION >= 61) {
if (ENABLE_ELEMENT_INTERNALS) {
if (typeof ElementInternals !== 'undefined') {
// ElementInternals API is supported in the browser
if (process.env.NATIVE_SHADOW) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { createElement } from 'lwc';
import { ENABLE_ELEMENT_INTERNALS } from 'test-utils';

import NotFormAssociated from 'x/notFormAssociated';
import FormAssociated from 'x/formAssociated';
import FormAssociatedFalse from 'x/formAssociatedFalse';

if (
process.env.API_VERSION >= 61 &&
ENABLE_ELEMENT_INTERNALS &&
typeof ElementInternals !== 'undefined' &&
!process.env.SYNTHETIC_SHADOW_ENABLED
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { createElement } from 'lwc';
import { ariaProperties, ariaAttributes } from 'test-utils';
import { ariaProperties, ariaAttributes, ENABLE_ELEMENT_INTERNALS } from 'test-utils';

import ElementInternal from 'ei/component';

if (
process.env.API_VERSION >= 61 &&
ENABLE_ELEMENT_INTERNALS &&
process.env.NATIVE_SHADOW &&
typeof ElementInternals !== 'undefined'
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createElement } from 'lwc';
import { nativeCustomElementLifecycleEnabled } from 'test-utils';
import { ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE } from 'test-utils';

import XBoundaryChildConstructorThrow from 'x/boundaryChildConstructorThrow';
import XBoundaryChildConnectedThrow from 'x/boundaryChildConnectedThrow';
Expand Down Expand Up @@ -372,7 +372,7 @@ describe('errorCallback throws after value mutation', () => {
'when child throws in connectedCallback',
'x-parent-throws-on-mutate-child-connected-throws',
XParentThrowsOnMutateChildConnectedThrows,
nativeCustomElementLifecycleEnabled
ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE
);
testStub(
'when child throws in constructor',
Expand All @@ -390,6 +390,6 @@ describe('errorCallback throws after value mutation', () => {
'when child throws in renderedCallback',
'x-parent-throws-on-mutate-child-rendered-throws',
XParentThrowsOnMutateChildRenderedThrows,
nativeCustomElementLifecycleEnabled
ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE
);
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createElement } from 'lwc';
import { nativeCustomElementLifecycleEnabled } from 'test-utils';
import { ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE, ENABLE_ELEMENT_INTERNALS } from 'test-utils';

import Container from 'face/container';
import FormAssociated from 'face/formAssociated';
Expand Down Expand Up @@ -52,7 +52,7 @@ const faceSanityTest = (tagName, ctor) => {
const container = document.body.querySelector('face-container');
container.shadowRoot.appendChild(form2);

if (process.env.API_VERSION >= 61) {
if (ENABLE_ELEMENT_INTERNALS) {
expect(face.internals.form.className).toEqual('form1');
expect(face2.internals.form.className).toEqual('form2');
}
Expand Down Expand Up @@ -105,7 +105,7 @@ const testFaceLifecycleMethodsNotCallable = (face) => {
};

if (typeof ElementInternals !== 'undefined') {
if (nativeCustomElementLifecycleEnabled) {
if (ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE) {
// native lifecycle enabled
describe('native lifecycle', () => {
if (process.env.NATIVE_SHADOW) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createElement } from 'lwc';
import { nativeCustomElementLifecycleEnabled } from 'test-utils';
import { ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE } from 'test-utils';

import Single from 'x/single';
import Parent from 'x/parent';
Expand Down Expand Up @@ -167,7 +167,7 @@ describe('invocation order', () => {

let expected;
if (testName === 'shadow' && process.env.NATIVE_SHADOW) {
if (nativeCustomElementLifecycleEnabled) {
if (ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE) {
expected = [
'foo-a:connectedCallback',
'foo-internal-a:connectedCallback',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { createElement } from 'lwc';
import {
attachReportingControlDispatcher,
detachReportingControlDispatcher,
nativeCustomElementLifecycleEnabled,
ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE,
} from 'test-utils';

import Component from 'x/component';
import Parent from 'x/parent';

if (!nativeCustomElementLifecycleEnabled) {
if (!ENABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE) {
describe('ConnectedCallbackWhileDisconnected reporting', () => {
let logger;
let dispatcher;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createElement } from 'lwc';
import { vFragBookEndEnabled } from 'test-utils';
import { USE_COMMENTS_FOR_FRAGMENT_BOOKENDS } from 'test-utils';

import MixedSlotParent from 'x/mixedSlotParent';

const vFragBookend = vFragBookEndEnabled ? '<!---->' : '';
const vFragBookend = USE_COMMENTS_FOR_FRAGMENT_BOOKENDS ? '<!---->' : '';

describe('if-block', () => {
it('should work when parent and child have matching slot types', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { createElement } from 'lwc';
import { lightDomSlotForwardingEnabled, vFragBookEndEnabled } from 'test-utils';
import { USE_LIGHT_DOM_SLOT_FORWARDING, USE_COMMENTS_FOR_FRAGMENT_BOOKENDS } from 'test-utils';

import BasicParent from 'x/basicParent';
import ParentOfChildWithForEach from 'x/parentOfChildWithForEach';
import ParentWNoSlotContent from 'x/parentWNoSlotContent';
import ParentOfChildWithNamedSlots from 'x/parentOfChildWithNamedSlots';
import NestedSlots from 'x/nestedSlots';

const vFragBookend = vFragBookEndEnabled ? '<!---->' : '';
const vFragBookend = USE_COMMENTS_FOR_FRAGMENT_BOOKENDS ? '<!---->' : '';

describe('scoped slots', () => {
it('scoped slots work with default slots', () => {
Expand Down Expand Up @@ -62,7 +62,7 @@ describe('scoped slots', () => {
// For standard slot content, "slot" attribute goes directly on the element unlike scoped
// slots where the attribute goes on the template tag
expect(child.querySelector('.slotname3').innerHTML).toBe(
lightDomSlotForwardingEnabled
USE_LIGHT_DOM_SLOT_FORWARDING
? `${vFragBookend}<p>MLB</p>${vFragBookend}`
: `${vFragBookend}<p slot="slotname3">MLB</p>${vFragBookend}`
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { createElement } from 'lwc';
import { vFragBookEndEnabled } from 'test-utils';
import { USE_COMMENTS_FOR_FRAGMENT_BOOKENDS } from 'test-utils';

import ParentWithScopedSlotContent from 'x/parentWithScopedSlotContent';
import ParentWithStandardSlotContent from 'x/parentWithStandardSlotContent';

const vFragBookend = vFragBookEndEnabled ? '<!---->' : '';
const vFragBookend = USE_COMMENTS_FOR_FRAGMENT_BOOKENDS ? '<!---->' : '';

describe('runtime validation of slot content and slot', () => {
it('Ignores content when parent uses scoped slot and child has standard slot', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { createElement } from 'lwc';
import { extractDataIds, lightDomSlotForwardingEnabled, vFragBookEndEnabled } from 'test-utils';
import {
extractDataIds,
USE_LIGHT_DOM_SLOT_FORWARDING,
USE_COMMENTS_FOR_FRAGMENT_BOOKENDS,
} from 'test-utils';

import LightContainer from './x/lightContainer/lightContainer';

Expand Down Expand Up @@ -39,7 +43,7 @@ const slotAssignmentWithoutForwarding = {
},
};

const expectedSlotAssignment = lightDomSlotForwardingEnabled
const expectedSlotAssignment = USE_LIGHT_DOM_SLOT_FORWARDING
? slotAssignmentWithForwarding
: slotAssignmentWithoutForwarding;

Expand Down Expand Up @@ -84,14 +88,14 @@ describe('slot forwarding', () => {
expect(remappedDefaultSlotContent[0].innerText).toEqual(expectedDefaultSlot.innerText);

// These are to cover API versions 60, 59 and below
const defaultSlotTextIndex = lightDomSlotForwardingEnabled
const defaultSlotTextIndex = USE_LIGHT_DOM_SLOT_FORWARDING
? 12
: vFragBookEndEnabled
: USE_COMMENTS_FOR_FRAGMENT_BOOKENDS
? 11
: 4;
const defaultSlotCommentIndex = lightDomSlotForwardingEnabled
const defaultSlotCommentIndex = USE_LIGHT_DOM_SLOT_FORWARDING
? 13
: vFragBookEndEnabled
: USE_COMMENTS_FOR_FRAGMENT_BOOKENDS
? 12
: 5;

Expand Down Expand Up @@ -128,7 +132,7 @@ describe('slot forwarding', () => {
expect(defaultSlotContent[1]).toEqual(commentNode);
}

if (lightDomSlotForwardingEnabled) {
if (USE_LIGHT_DOM_SLOT_FORWARDING) {
// With slot forwarding
const reassginedDefaultSlot = slots['default-slot-reassigned'].assignedNodes();
// Verify static vnode `slot` attribute is reassigned
Expand All @@ -155,7 +159,7 @@ describe('slot forwarding', () => {
// slot attribute to be remapped to the slot attribute on the light DOM slot.
// Verify the slot attribute was correctly updated.
// Api versions < 61 slot forwarding is not enabled, so the slot attribute is untouched
expect(upperSlot.hasAttribute('slot')).toBe(!lightDomSlotForwardingEnabled);
expect(upperSlot.hasAttribute('slot')).toBe(!USE_LIGHT_DOM_SLOT_FORWARDING);

const upperSlotContent = upperSlot.assignedNodes();
// Note that because the shadow slot is passed, the slot element is what's updated.
Expand All @@ -166,7 +170,7 @@ describe('slot forwarding', () => {
expect(upperSlotContent[1].innerText).toEqual(expectedUpperSlot.content);

const lowerSlot = slots['lower-slot'];
expect(lowerSlot.hasAttribute('slot')).toBe(!lightDomSlotForwardingEnabled);
expect(lowerSlot.hasAttribute('slot')).toBe(!USE_LIGHT_DOM_SLOT_FORWARDING);

const lowerSlotContent = lowerSlot.assignedNodes();
expect(lowerSlotContent[0].getAttribute('slot')).toBe('upper');
Expand All @@ -175,7 +179,7 @@ describe('slot forwarding', () => {
expect(lowerSlotContent[1].innerText).toEqual(expectedLowerSlot.content);

const defaultSlot = slots['default-slot'];
expect(defaultSlot.hasAttribute('slot')).toBe(!lightDomSlotForwardingEnabled);
expect(defaultSlot.hasAttribute('slot')).toBe(!USE_LIGHT_DOM_SLOT_FORWARDING);

// Note since the content forwarded to the default shadow slot are wrapped in an actual slot element,
// all content inside of it is forwarded together.
Expand Down
Loading

0 comments on commit ccd0253

Please sign in to comment.