Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(Button): auto generate visual test #1623

Merged
merged 10 commits into from
Aug 14, 2024
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 30 additions & 1 deletion src/components/Button/__tests__/Button.visual.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,21 @@ import React from 'react';

import {test} from '~playwright/core';

import {createSmokeScenarios} from '../../../stories/tests-factory/create-smoke-scenarios';
import {Button} from '../Button';

import {
defaultProps,
disabledCases,
loadingCases,
pinsCases,
selectedCases,
sizeCases,
viewsCases,
} from './cases';
import {ButtonStories, CustomIconSizeButton} from './helpersPlaywright';

test.describe('Button', () => {
test.describe('Button', {tag: '@Button'}, () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a tag for the component so that you can run tests for one or more components

test('render story: <Default>', async ({mount, expectScreenshot}) => {
await mount(<ButtonStories.Default />);

Expand Down Expand Up @@ -76,4 +88,21 @@ test.describe('Button', () => {

await expectScreenshot();
});

const smokeScenarios = createSmokeScenarios(defaultProps, {
size: sizeCases,
selected: selectedCases,
disabled: disabledCases,
loading: loadingCases,
view: viewsCases,
pin: pinsCases,
});

smokeScenarios.forEach(([title, details, props]) => {
test(title, details, async ({mount, expectScreenshot}) => {
await mount(<Button {...props} />);

await expectScreenshot();
});
});
});
61 changes: 61 additions & 0 deletions src/components/Button/__tests__/cases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type {CasesWithName} from '../../../stories/tests-factory/models';
import type {ButtonProps} from '../Button';

export const defaultProps: ButtonProps = {
children: 'Text',
};

export const sizeCases: CasesWithName<ButtonProps['size']> = [
['xs', 'xs'],
['s', 's'],
['m', 'm'],
['l', 'l'],
['xl', 'xl'],
];

export const selectedCases: CasesWithName<ButtonProps['selected']> = [['selected', true]];

export const disabledCases: CasesWithName<ButtonProps['disabled']> = [['disabled', true]];

export const loadingCases: CasesWithName<ButtonProps['loading']> = [['loading', true]];

export const viewsCases: CasesWithName<ButtonProps['view']> = [
['normal', 'normal'],
['action', 'action'],
['outlined', 'outlined'],
['outlined-info', 'outlined-info'],
['outlined-success', 'outlined-success'],
['outlined-warning', 'outlined-warning'],
['outlined-danger', 'outlined-danger'],
['outlined-utility', 'outlined-utility'],
['outlined-action', 'outlined-action'],
['raised', 'raised'],
['flat', 'flat'],
['flat-secondary', 'flat-secondary'],
['flat-info', 'flat-info'],
['flat-success', 'flat-success'],
['flat-warning', 'flat-warning'],
['flat-danger', 'flat-danger'],
['flat-utility', 'flat-utility'],
['flat-action', 'flat-action'],
['normal-contrast', 'normal-contrast'],
['outlined-contrast', 'outlined-contrast'],
['flat-contrast', 'flat-contrast'],
];

export const pinsCases: CasesWithName<ButtonProps['pin']> = [
['round-round', 'round-round'],
['brick-brick', 'brick-brick'],
['clear-clear', 'clear-clear'],
['circle-circle', 'circle-circle'],
['round-brick', 'round-brick'],
['brick-round', 'brick-round'],
['round-clear', 'round-clear'],
['clear-round', 'clear-round'],
['brick-clear', 'brick-clear'],
['clear-brick', 'clear-brick'],
['circle-brick', 'circle-brick'],
['brick-circle', 'brick-circle'],
['circle-clear', 'circle-clear'],
['clear-circle', 'clear-circle'],
];
2 changes: 1 addition & 1 deletion src/components/Label/__tests__/Label.visual.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ test.describe('Label', () => {
await expectScreenshot();
});

test('render story: <ShowcaseStory>', async ({mount, expectScreenshot}) => {
test.skip('render story: <ShowcaseStory>', async ({mount, expectScreenshot}) => {
await mount(<LabelStories.ShowcaseStory />);

await expectScreenshot();
Expand Down
138 changes: 138 additions & 0 deletions src/stories/tests-factory/create-smoke-scenarios.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import {createSmokeScenarios} from './create-smoke-scenarios';

test('regular', () => {
const smokeScenarious = createSmokeScenarios(
{
theme: 'theme-1',
label: 'label-1',
},
{
theme: ['theme-2', 'theme-3'],
label: ['label-2', 'label-3'],
},
);

expect(smokeScenarious).toEqual([
[
'smoke',
{tag: ['@smoke']},
{
label: 'label-1',
theme: 'theme-1',
},
],
[
'smoke-theme-theme-2',
{tag: ['@smoke']},
{
label: 'label-1',
theme: 'theme-2',
},
],
[
'smoke-theme-theme-3',
{tag: ['@smoke']},
{
label: 'label-1',
theme: 'theme-3',
},
],
[
'smoke-label-label-2',
{tag: ['@smoke']},
{
label: 'label-2',
theme: 'theme-1',
},
],
[
'smoke-label-label-3',
{tag: ['@smoke']},
{
label: 'label-3',
theme: 'theme-1',
},
],
]);
});

test('with scenario name', () => {
const smokeScenarious = createSmokeScenarios(
{
theme: 'theme-1',
label: 'label-1',
},
{
theme: [
['name-theme-2', 'theme-2'],
['name-theme-3', 'theme-3'],
],
label: [
['name-label-2', 'label-2'],
['name-label-3', 'label-3'],
],
},
);

expect(smokeScenarious).toEqual([
[
'smoke',
{tag: ['@smoke']},
{
label: 'label-1',
theme: 'theme-1',
},
],
[
'smoke-theme-name-theme-2',
{tag: ['@smoke']},
{
label: 'label-1',
theme: 'theme-2',
},
],
[
'smoke-theme-name-theme-3',
{tag: ['@smoke']},
{
label: 'label-1',
theme: 'theme-3',
},
],
[
'smoke-label-name-label-2',
{tag: ['@smoke']},
{
label: 'label-2',
theme: 'theme-1',
},
],
[
'smoke-label-name-label-3',
{tag: ['@smoke']},
{
label: 'label-3',
theme: 'theme-1',
},
],
]);
});

test('with additionalTags option', () => {
const smokeScenarious = createSmokeScenarios(
{
theme: 'theme-1',
},
{
theme: [['name-theme-2', 'theme-2']],
},
{
additionalTags: ['@custom-tag-1'],
},
);

expect(smokeScenarious).toEqual([
['smoke', {tag: ['@smoke', '@custom-tag-1']}, {theme: 'theme-1'}],
['smoke-theme-name-theme-2', {tag: ['@smoke', '@custom-tag-1']}, {theme: 'theme-2'}],
]);
});
72 changes: 72 additions & 0 deletions src/stories/tests-factory/create-smoke-scenarios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import type {Cases, CasesWithName, Scenario, ScenarioDetails} from './models';

interface Options {
additionalTags?: Array<string>;
}

function checkIsCasesWithName<T>(cases: CasesWithName<T> | Cases<T>): cases is CasesWithName<T> {
const firstCase = cases[0] || null;
return Array.isArray(firstCase) && firstCase.length === 2;
}

export const createSmokeScenarios = <Props extends {}>(
baseProps: Props,
propsCases: {
[K in Partial<keyof Props>]: CasesWithName<Props[K]> | Cases<Props[K]>;
},
options?: Options,
) => {
const scenarioDetails: ScenarioDetails = {
tag: ['@smoke', ...(options?.additionalTags || [])],
};

const scenarios: Array<Scenario<Props>> = [
[
'smoke',
scenarioDetails,
{
...baseProps,
},
],
];

const propNames = Object.keys(propsCases) as Array<keyof Props>;
propNames.forEach((propName) => {
const propCases = propsCases[propName];

if (checkIsCasesWithName(propCases)) {
propCases.forEach((propCase) => {
const [caseName, caseProps] = propCase;

scenarios.push([
`smoke-${propName as string}-${caseName}`,
scenarioDetails,
{
...baseProps,
[propName]: caseProps,
},
]);
});
} else {
propCases.forEach((propCase) => {
const hasStringifyMethod = (propCase as any)?.toString;
if (!hasStringifyMethod) {
throw new Error(
'The case value does not have a method "toString", use case with name.',
);
}

scenarios.push([
`smoke-${propName as string}-${(propCase as any)?.toString()}`,
scenarioDetails,
{
...baseProps,
[propName]: propCase,
},
]);
});
}
});

return scenarios;
};
7 changes: 7 additions & 0 deletions src/stories/tests-factory/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type CaseName = string;
export type Cases<T> = Array<T>;
export type CasesWithName<T> = Array<[CaseName, T]>;

export type ScenarioName = string;
export type ScenarioDetails = {tag: Array<string>};
export type Scenario<T> = [ScenarioName, ScenarioDetails, T];
Loading