Skip to content

Commit

Permalink
refactor: reduce tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kyubisation committed May 14, 2024
1 parent 2414324 commit 42cf6c2
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 44 deletions.
17 changes: 9 additions & 8 deletions src/components/button/button/button.snapshot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ import {
isVisualRegressionRun,
visualRegressionSnapshot,
} from '../../core/testing/private.js';
import type { SbbButtonSize } from '../common.js';

import './button.js';

describe(`sbb-button`, () => {
if (isVisualRegressionRun()) {
describe('visual-regression', () => {
const cases = {
size: ['s', 'm', 'l'] as SbbButtonSize[],
disabled: [false, true],
negative: [false, true],
iconName: [undefined, 'arrow-right-small'],
state: [
{ icon: undefined, text: 'Button' },
{ icon: 'arrow-right-small', text: 'Button' },
{ icon: 'arrow-right-small', text: '' },
],
};

describeViewports(() => {
describeEach(cases, ({ size, disabled, negative, iconName }) => {
describeViewports({ viewports: ['zero', 'medium'] }, () => {
describeEach(cases, ({ disabled, negative, state }) => {
let root: HTMLElement;
beforeEach(async () => {
root = await fixture(html`
Expand All @@ -33,11 +35,10 @@ describe(`sbb-button`, () => {
>
<sbb-button
style="--sbb-button-transition-duration:0s;--sbb-button-transition-easing-function:0s;"
size=${size}
?disabled=${disabled}
?negative=${negative}
.iconName=${iconName}
>Button</sbb-button
.iconName=${state.icon}
>${state.text}</sbb-button
>
</div>
`);
Expand Down
20 changes: 12 additions & 8 deletions src/components/core/testing/private/describe-each.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
function generateDescribeName(payload: Record<string, unknown>): string {
return Object.entries(payload)
.map(
([key, value]) =>
`${key}=${typeof value === 'object' && value ? `(${generateDescribeName(value as Record<string, unknown>)})` : value}`,
)
.join(', ');
}

function partialDescribeEach<T extends Record<string, unknown[]>>(
cases: T,
payload: Record<keyof T, unknown>,
Expand All @@ -16,14 +25,9 @@ function partialDescribeEach<T extends Record<string, unknown[]>>(
} else {
for (const value of values) {
const finalPayload = { ...payload, [key]: value };
describe(
Object.entries(finalPayload)
.map(([key, value]) => `${key}=${value}`)
.join(', '),
function () {
suiteRun.call(this, finalPayload);
},
);
describe(generateDescribeName(finalPayload), function () {
suiteRun.call(this, finalPayload);
});
}
}
}
Expand Down
30 changes: 26 additions & 4 deletions src/components/core/testing/private/describe-viewports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,35 @@ const viewportSizes = {
large: SbbBreakpointLargeMin,
wide: SbbBreakpointWideMin,
ultra: SbbBreakpointUltraMin,
};
} as const;

export function describeViewports(fn: (this: Mocha.Suite) => void, viewportHeight = 400): void {
for (const [size, value] of Object.entries(viewportSizes)) {
export interface DescribeViewportOptions {
viewports?: (keyof typeof viewportSizes)[];
viewportHeight?: number;
}

export function describeViewports(
options: DescribeViewportOptions,
fn: (this: Mocha.Suite) => void,
): void;
export function describeViewports(fn: (this: Mocha.Suite) => void): void;
export function describeViewports(
optionsOrFn: DescribeViewportOptions | ((this: Mocha.Suite) => void),
fn?: (this: Mocha.Suite) => void,
): void {
const options = typeof optionsOrFn === 'object' ? optionsOrFn : {};
fn ??= optionsOrFn as (this: Mocha.Suite) => void;
let viewportSizeTests = Object.entries(viewportSizes);
if (options.viewports?.length) {
viewportSizeTests = viewportSizeTests.filter(([key, _value]) =>
options.viewports?.includes(key as keyof typeof viewportSizes),
);
}

for (const [size, value] of viewportSizeTests) {
describe(`viewport=${size}`, function () {
before(async () => {
await setViewport({ width: value, height: viewportHeight });
await setViewport({ width: value, height: options.viewportHeight ?? 400 });
});

fn.call(this);
Expand Down
64 changes: 45 additions & 19 deletions src/components/core/testing/private/visual-regression-snapshot.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,67 @@
import { sendKeys, sendMouse } from '@web/test-runner-commands';
import { resetMouse, sendKeys, sendMouse } from '@web/test-runner-commands';
import { visualDiff } from '@web/test-runner-visual-regression';

export function imageName(test: Mocha.Runnable): string {
return test!.fullTitle().replaceAll(', ', '-').replaceAll(' ', '_');
}

export function visualRegressionSnapshot(snapshotElement: () => HTMLElement): void {
function findElementCenter(snapshotElement: () => HTMLElement): [number, number] {
const element = snapshotElement();
// Look for the first sbb-* element and get center of the element to
// move the mouse cursor over it.
const positionElement = element.localName.startsWith('sbb-')
? element
: element.firstElementChild!;
const position = positionElement.getBoundingClientRect();
return [
Math.round(position.x + position.width / 2),
Math.round(position.y + position.height / 2),
];
}

export function testVisualDiff(snapshotElement: () => HTMLElement): void {
it('default', async function () {
await visualDiff(snapshotElement(), imageName(this.test!));
});
}

export function testVisualDiffFocus(snapshotElement: () => HTMLElement): void {
it('focus', async function () {
await sendKeys({ press: 'Tab' });
await visualDiff(snapshotElement(), imageName(this.test!));
});
}

export function testVisualDiffHover(snapshotElement: () => HTMLElement): void {
it('hover', async function () {
const element = snapshotElement();
const positionElement = element.localName.startsWith('sbb-')
? element
: element.firstElementChild!;
const position = positionElement.getBoundingClientRect();
await sendMouse({
type: 'move',
position: [
Math.round(position.x + position.width / 2),
Math.round(position.y + position.height / 2),
],
});
const position = findElementCenter(snapshotElement);

try {
await visualDiff(element, imageName(this.test!));
await sendMouse({ type: 'move', position });
await visualDiff(snapshotElement(), imageName(this.test!));
} finally {
await sendMouse({
type: 'move',
position: [0, 0],
});
await resetMouse();
}
});
}

export function testVisualDiffActive(snapshotElement: () => HTMLElement): void {
it('active', async function () {
const position = findElementCenter(snapshotElement);

try {
await sendMouse({ type: 'move', position });
await sendMouse({ type: 'down' });
await visualDiff(snapshotElement(), imageName(this.test!));
} finally {
await resetMouse();
}
});
}

export function visualRegressionSnapshot(snapshotElement: () => HTMLElement): void {
testVisualDiff(snapshotElement);
testVisualDiffFocus(snapshotElement);
testVisualDiffHover(snapshotElement);
testVisualDiffActive(snapshotElement);
}
19 changes: 14 additions & 5 deletions src/components/core/testing/test-setup.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import { getSvgContent } from '../../icon.js';
import { sbbInputModalityDetector } from '../a11y.js';
import type { SbbIconConfig } from '../config.js';
import { mergeConfig } from '../config.js';

import { isHydratedSsr, isVisualRegressionRun } from './private.js';

function setupIconConfig(): void {
if (isVisualRegressionRun()) {
const preloadedIcons = ['arrow-right-small'];
await Promise.all(preloadedIcons.map((icon) => getSvgContent('default', icon, true)));

mergeConfig({
icon: {
interceptor({ namespace, name }) {
throw new Error(`Icon ${namespace}:${name} must be preloaded in test-setup.ts!`);
},
},
});
} else {
// Setup mock configuration for icons
const testNamespaces = ['default', 'picto'];
const icon: SbbIconConfig = {
interceptor: ({ namespace, name, request }) => {
Expand All @@ -27,10 +40,6 @@ function setupIconConfig(): void {
mergeConfig({ icon });
}

if (!isVisualRegressionRun()) {
setupIconConfig();
}

if (isHydratedSsr()) {
await import('@lit-labs/ssr-client/lit-element-hydrate-support.js');
}
Expand Down

0 comments on commit 42cf6c2

Please sign in to comment.