Skip to content

Commit

Permalink
Refactor Style tests (#858)
Browse files Browse the repository at this point in the history
  • Loading branch information
MonicaOlejniczak authored Oct 19, 2021
1 parent 6a1a779 commit 71da8c0
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 59 deletions.
148 changes: 91 additions & 57 deletions packages/react/src/runtime/__tests__/style.test.tsx
Original file line number Diff line number Diff line change
@@ -1,103 +1,137 @@
import React from 'react';
import type { ComponentType } from 'react';
import { render } from '@testing-library/react';
import Style from '../style';

jest.mock('../is-node', () => ({
isNodeEnvironment: () => false,
}));

describe('<Style />', () => {
let consoleErrorSpy: jest.SpyInstance;

beforeEach(() => {
// Reset style tags in head before each test so that it will remove styles
// injected by test
document.head.querySelectorAll('style').forEach((styleElement) => {
styleElement.textContent = '';
});
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
});

afterEach(() => {
consoleErrorSpy.mockRestore();
document.head.innerHTML = '';
});

// We want to isolate the test to correctly mimic the environment being loaded in once
const createIsolatedTest = (callback: (Style: ComponentType) => void) => {
jest.isolateModules(() => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Style = require('../style');

callback(Style.default);
});
};

it('should render nothing on the client', () => {
const { baseElement } = render(<Style>{[`.a { display: block; }`]}</Style>);
createIsolatedTest((Style) => {
const { baseElement } = render(<Style>{[`.a { display: block; }`]}</Style>);

expect(baseElement.getElementsByTagName('style')).toHaveLength(0);
expect(baseElement.getElementsByTagName('style')).toHaveLength(0);
expect(console.error).not.toHaveBeenCalled();
});
});

it('should add style to the head on the client', () => {
render(<Style>{[`.b { display: block; }`]}</Style>);
createIsolatedTest((Style) => {
render(<Style>{[`.b { display: block; }`]}</Style>);

expect(document.head.innerHTML).toInclude('<style>.b { display: block; }</style>');
expect(document.head.innerHTML).toInclude('<style>.b { display: block; }</style>');
expect(console.error).not.toHaveBeenCalled();
});
});

it('should only add one style if it was already added', () => {
render(<Style>{[`.c { display: block; }`]}</Style>);
render(<Style>{[`.c { display: block; }`]}</Style>);
createIsolatedTest((Style) => {
render(<Style>{[`.c { display: block; }`]}</Style>);
render(<Style>{[`.c { display: block; }`]}</Style>);

expect(document.head.innerHTML).toIncludeRepeated('<style>.c { display: block; }</style>', 1);
expect(document.head.innerHTML).toIncludeRepeated('<style>.c { display: block; }</style>', 1);
expect(console.error).not.toHaveBeenCalled();
});
});

it('should noop in prod', () => {
jest.spyOn(console, 'error');
process.env.NODE_ENV = 'production';
createIsolatedTest((Style) => {
process.env.NODE_ENV = 'production';

render(<Style>{[`.c:first-child { display: block; }`]}</Style>);
render(<Style>{[`.c:first-child { display: block; }`]}</Style>);

expect(console.error).not.toHaveBeenCalled();
expect(console.error).not.toHaveBeenCalled();
});
});

it('should warn in dev when using a dangerous pseduo selector', () => {
jest.spyOn(console, 'error');
process.env.NODE_ENV = 'development';
createIsolatedTest((Style) => {
process.env.NODE_ENV = 'development';

render(<Style>{[`.c:first-child { display: block; }`]}</Style>);
render(<Style>{[`.c:first-child { display: block; }`]}</Style>);

expect(console.error).toHaveBeenCalled();
expect(console.error).toHaveBeenCalledTimes(1);
});
});

it('should warn in dev only once', () => {
jest.spyOn(console, 'error');
process.env.NODE_ENV = 'development';
createIsolatedTest((Style) => {
process.env.NODE_ENV = 'development';

render(<Style>{[`.c:first-child { display: block; }`]}</Style>);
render(<Style>{[`.c:first-child { display: block; }`]}</Style>);
render(<Style>{[`.c:first-child { display: block; }`]}</Style>);
render(<Style>{[`.c:first-child { display: block; }`]}</Style>);

expect(console.error).toHaveBeenCalledTimes(1);
expect(console.error).toHaveBeenCalledTimes(1);
expect(console.error).toHaveBeenCalledWith(
expect.stringMatching('Selectors ":first-child, :nth-child" are dangerous to use')
);
});
});

it('should render style tags in buckets', () => {
render(
<Style>
{[
`._a1234567:hover{ color: red; }`,
`._b1234567:active{ color: blue; }`,
`._c1234567:link{ color: green; }`,
`._d1234567{ display: block; }`,
`@media (max-width: 800px){ ._e1234567{ color: yellow; } }`,
`._f1234567:focus{ color: pink; }`,
`._g1234567:visited{ color: grey; }`,
`._h1234567:focus-visible{ color: white; }`,
`._i1234567:focus-within{ color: black; }`,
]}
</Style>
);

expect(document.head.innerHTML.split('</style>').join('</style>\n')).toMatchInlineSnapshot(`
"<style>._d1234567{ display: block; }</style>
<style>._c1234567:link{ color: green; }</style>
<style>._g1234567:visited{ color: grey; }</style>
<style>._i1234567:focus-within{ color: black; }</style>
<style>._f1234567:focus{ color: pink; }</style>
<style>._h1234567:focus-visible{ color: white; }</style>
<style>._a1234567:hover{ color: red; }</style>
<style>._b1234567:active{ color: blue; }</style>
<style>@media (max-width: 800px){ ._e1234567{ color: yellow; } }</style>
"
`);
createIsolatedTest((Style) => {
render(
<Style>
{[
`._a1234567:hover{ color: red; }`,
`._b1234567:active{ color: blue; }`,
`._c1234567:link{ color: green; }`,
`._d1234567{ display: block; }`,
`@media (max-width: 800px){ ._e1234567{ color: yellow; } }`,
`._f1234567:focus{ color: pink; }`,
`._g1234567:visited{ color: grey; }`,
`._h1234567:focus-visible{ color: white; }`,
`._i1234567:focus-within{ color: black; }`,
]}
</Style>
);

expect(document.head.innerHTML.split('</style>').join('</style>\n')).toMatchInlineSnapshot(`
"<style>._d1234567{ display: block; }</style>
<style>._c1234567:link{ color: green; }</style>
<style>._g1234567:visited{ color: grey; }</style>
<style>._i1234567:focus-within{ color: black; }</style>
<style>._f1234567:focus{ color: pink; }</style>
<style>._h1234567:focus-visible{ color: white; }</style>
<style>._a1234567:hover{ color: red; }</style>
<style>._b1234567:active{ color: blue; }</style>
<style>@media (max-width: 800px){ ._e1234567{ color: yellow; } }</style>
"
`);
expect(console.error).not.toHaveBeenCalled();
});
});

it('should update styles', () => {
const { rerender } = render(<Style>{[`.first-render { display: block; }`]}</Style>);
createIsolatedTest((Style) => {
const { rerender } = render(<Style>{[`.first-render { display: block; }`]}</Style>);

rerender(<Style>{[`.second-render { display: block; }`]}</Style>);
rerender(<Style>{[`.second-render { display: block; }`]}</Style>);

expect(document.head.innerHTML).toInclude('.second-render { display: block; }');
expect(document.head.innerHTML).toInclude('.second-render { display: block; }');
expect(console.error).not.toHaveBeenCalled();
});
});
});
1 change: 0 additions & 1 deletion packages/react/src/runtime/dev-warnings.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@
* Flowgen v1.14.1
* @flow
*/
declare export var warn: (str: string, ...args: any[]) => void;
declare export var analyzeCssInDev: (sheet: string) => void;
2 changes: 1 addition & 1 deletion packages/react/src/runtime/dev-warnings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const selectorsToWarn = [':first-child', ':nth-child'];
const hasWarned: Record<string, true> = {};

export const warn = (str: string, ...args: any[]): void =>
const warn = (str: string, ...args: any[]): void =>
console.error(
`
██████╗ ██████╗ ███╗ ███╗██████╗ ██╗██╗ ███████╗██████╗
Expand Down

0 comments on commit 71da8c0

Please sign in to comment.