Skip to content

Commit

Permalink
Tests: Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Feb 3, 2019
1 parent f7a6963 commit c908432
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 80 deletions.
147 changes: 67 additions & 80 deletions test/lazy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const React = require('react'),
{Suspense} = React;

// Imports
const {itRenders, lazy, removeSpacing} = require('./utils');
const {itRenders, lazy, makeLazy, initPromises, removeSpacing} = require('./utils');

// Globals
const spy = jest.fn;
Expand Down Expand Up @@ -106,9 +106,9 @@ describe('lazy component', () => {
});

itRenders('rejects when promise marked no SSR and fallback throws promise marked no SSR', async ({render}) => {
const promises = initPromises();
const Lazy = lazy(() => <div>Lazy inner</div>, {noSsr: true});
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const LazyFallback = () => {throw promise;};
const LazyFallback = makeLazy('LazyFallback', {noSsr: true});

const e = (
<div>
Expand All @@ -123,7 +123,7 @@ describe('lazy component', () => {
);

const p = render(e);
await expect(p).rejects.toBe(promise);
await expect(p).rejects.toBe(promises.LazyFallback);
});
});

Expand Down Expand Up @@ -220,10 +220,11 @@ describe('lazy component', () => {
});

itRenders('rejects when promise marked no SSR and both fallbacks throw promises marked no SSR', async ({render}) => {
const promises = initPromises();

const Lazy = lazy(() => <div>Lazy inner</div>, {noSsr: true});
const LazyFallbackInner = lazy(() => <div>Lazy fallback</div>, {noSsr: true});
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const LazyFallbackOuter = () => {throw promise;};
const LazyFallbackOuter = makeLazy('LazyFallbackOuter', {noSsr: true});

const e = (
<div>
Expand All @@ -242,7 +243,7 @@ describe('lazy component', () => {
);

const p = render(e);
await expect(p).rejects.toBe(promise);
await expect(p).rejects.toBe(promises.LazyFallbackOuter);
});
});

Expand All @@ -264,12 +265,13 @@ describe('lazy component', () => {
});

itRenders('rejects when promise marked no SSR', async ({render}) => {
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const Lazy = () => {throw promise;};
const promises = initPromises();

const Lazy = makeLazy('Lazy', {noSsr: true});
const e = <div><Lazy/></div>;

const p = render(e);
await expect(p).rejects.toBe(promise);
await expect(p).rejects.toBe(promises.Lazy);
});
});
});
Expand Down Expand Up @@ -385,8 +387,7 @@ describe('multiple lazy components', () => {
describe('inside suspense', () => {
itRenders('renders fallback', async ({render, openTag}) => {
const Lazy1 = lazy(() => <div>Lazy inner 1</div>);
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const Lazy2 = () => {throw promise;};
const Lazy2 = lazy(() => <div>Lazy inner 2</div>, {noSsr: true});
const Lazy3 = lazy(() => <div>Lazy inner 3</div>);

const e = (
Expand Down Expand Up @@ -446,25 +447,12 @@ describe('multiple lazy components', () => {
});

itRenders('calls `.abort()` on all promises inside suspense', async ({render, openTag}) => {
const promises = [];
function makeLazy(num, noSsr) {
let loaded = false, promise;
return function LazyComponent() {
if (loaded) return <div>{`Lazy inner ${num}`}</div>;
if (!promise) {
promise = new Promise(resolve => resolve()).then(() => loaded = true);
if (noSsr) promise.noSsr = true;
promise.abort = spy();
promises[num - 1] = promise;
}
throw promise;
};
}

const Lazy1 = makeLazy(1);
const Lazy2 = makeLazy(2, true);
const Lazy3 = makeLazy(3);
const Lazy4 = makeLazy(4);
const promises = initPromises();

const Lazy1 = makeLazy('Lazy1');
const Lazy2 = makeLazy('Lazy2', {noSsr: true});
const Lazy3 = makeLazy('Lazy3');
const Lazy4 = makeLazy('Lazy4');

const e = (
<div>
Expand All @@ -479,21 +467,23 @@ describe('multiple lazy components', () => {

const p = render(e);

expect(promises[0].abort).toHaveBeenCalledTimes(1);
expect(promises[1].abort).toHaveBeenCalledTimes(1);
expect(promises[2]).toBeUndefined();
expect(promises[3].abort).not.toHaveBeenCalled();
expect(promises.Lazy1.abort).toHaveBeenCalledTimes(1);
expect(promises.Lazy2.abort).toHaveBeenCalledTimes(1);
expect(promises.Lazy3).toBeUndefined();
expect(promises.Lazy4.abort).not.toHaveBeenCalled();

const h = await p;
expect(h).toBe(`<div${openTag}><span>Fallback</span><div>Lazy inner 4</div></div>`);
expect(h).toBe(`<div${openTag}><span>Fallback</span><div>Lazy inner Lazy4</div></div>`);
});
});

describe('outside suspense', () => {
let promises;
beforeEach(() => promises = initPromises());

itRenders('rejects promise', async ({render}) => {
const Lazy1 = lazy(() => <div>Lazy inner 1</div>);
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const Lazy2 = () => {throw promise;};
const Lazy2 = makeLazy('Lazy2', {noSsr: true});
const Lazy3 = lazy(() => <div>Lazy inner 3</div>);

const e = (
Expand All @@ -505,13 +495,12 @@ describe('multiple lazy components', () => {
);

const p = render(e);
await expect(p).rejects.toBe(promise);
await expect(p).rejects.toBe(promises.Lazy2);
});

itRenders('prevents later elements being rendered', async ({render}) => {
const Lazy1 = spy(lazy(() => <div>Lazy inner 1</div>));
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const Lazy2 = spy(() => {throw promise;});
const Lazy2 = spy(makeLazy('Lazy2', {noSsr: true}));
const Lazy3 = spy(lazy(() => <div>Lazy inner 3</div>));

const e = (
Expand All @@ -528,28 +517,15 @@ describe('multiple lazy components', () => {
expect(Lazy2).toHaveBeenCalled();
expect(Lazy3).not.toHaveBeenCalled();

await expect(p).rejects.toBe(promise);
await expect(p).rejects.toBe(promises.Lazy2);
});

itRenders('calls `.abort()` on all promises', async ({render}) => {
const promises = [];
function makeLazy(num, noSsr) {
let loaded = false, promise;
return function LazyComponent() {
if (loaded) return <div>{`Lazy inner ${num}`}</div>;
if (!promise) {
promise = new Promise(resolve => resolve()).then(() => loaded = true);
if (noSsr) promise.noSsr = true;
promise.abort = spy();
promises[num - 1] = promise;
}
throw promise;
};
}

const Lazy1 = makeLazy(1);
const Lazy2 = makeLazy(2, true);
const Lazy3 = makeLazy(3);
const promises = initPromises();

const Lazy1 = makeLazy('Lazy1');
const Lazy2 = makeLazy('Lazy2', {noSsr: true});
const Lazy3 = makeLazy('Lazy3');

const e = (
<div>
Expand All @@ -561,11 +537,11 @@ describe('multiple lazy components', () => {

const p = render(e);

expect(promises[0].abort).toHaveBeenCalledTimes(1);
expect(promises[1].abort).toHaveBeenCalledTimes(1);
expect(promises[2]).toBeUndefined();
expect(promises.Lazy1.abort).toHaveBeenCalledTimes(1);
expect(promises.Lazy2.abort).toHaveBeenCalledTimes(1);
expect(promises.Lazy3).toBeUndefined();

await expect(p).rejects.toBe(promises[1]);
await expect(p).rejects.toBe(promises.Lazy2);
});
});
});
Expand Down Expand Up @@ -609,10 +585,14 @@ describe('nested lazy components', () => {
});

describe('rejects when promise marked no SSR', function() {
let promises;
beforeEach(() => promises = initPromises());

itRenders('when nested 1 deep', async ({render}) => {
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const Lazy2 = () => {throw promise;};
const Lazy = lazy(() => <div>Before Lazy Layer 1<Lazy2/>After Lazy Layer 1</div>);
const LazyInner = makeLazy('LazyInner', {noSsr: true});
const Lazy = makeLazy('Lazy', {
element: <div>Before Lazy Layer 1<LazyInner/>After Lazy Layer 1</div>
});
const e = (
<div>
<div>Before Lazy</div>
Expand All @@ -622,14 +602,18 @@ describe('nested lazy components', () => {
);

const p = render(e);
await expect(p).rejects.toBe(promise);
await promises.Lazy;
await expect(p).rejects.toBe(promises.LazyInner);
});

itRenders('when nested 2 deep', async ({render}) => {
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const Lazy3 = () => {throw promise;};
const Lazy2 = lazy(() => <div>Before Lazy Layer 2<Lazy3/>After Lazy Layer 2</div>);
const Lazy = lazy(() => <div>Before Lazy Layer 1<Lazy2/>After Lazy Layer 1</div>);
const LazyInnerInner = makeLazy('LazyInnerInner', {noSsr: true});
const LazyInner = makeLazy('LazyInner', {
element: <div>Before Lazy Layer 2<LazyInnerInner/>After Lazy Layer 2</div>
});
const Lazy = makeLazy('Lazy', {
element: <div>Before Lazy Layer 1<LazyInner/>After Lazy Layer 1</div>
});
const e = (
<div>
<div>Before Lazy</div>
Expand All @@ -639,15 +623,17 @@ describe('nested lazy components', () => {
);

const p = render(e);
await expect(p).rejects.toBe(promise);
await promises.Lazy;
await promises.LazyInner;
await expect(p).rejects.toBe(promises.LazyInnerInner);
});
});

describe('renders fallback when promise marked no SSR', function() {
itRenders('when nested 1 deep', async ({render, openTag}) => {
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const Lazy2 = () => {throw promise;};
const Lazy = lazy(() => <div>Before Lazy Layer 1<Lazy2/>After Lazy Layer 1</div>);
const LazyInner = lazy(() => <div>Lazy inner</div>, {noSsr: true});
const Lazy = lazy(() => <div>Before Lazy Layer 1<LazyInner/>After Lazy Layer 1</div>);

const e = (
<div>
<div>Before Suspense</div>
Expand All @@ -671,10 +657,11 @@ describe('nested lazy components', () => {
});

itRenders('when nested 2 deep', async ({render, openTag}) => {
const promise = Object.assign(new Promise(resolve => resolve()), {noSsr: true});
const Lazy3 = () => {throw promise;};
const Lazy2 = lazy(() => <div>Before Lazy Layer 2<Lazy3/>After Lazy Layer 2</div>);
const Lazy = lazy(() => <div>Before Lazy Layer 1<Lazy2/>After Lazy Layer 1</div>);
const LazyInnerInner = lazy(() => <div>Lazy inner</div>, {noSsr: true});
const LazyInner = lazy(
() => <div>Before Lazy Layer 2<LazyInnerInner/>After Lazy Layer 2</div>
);
const Lazy = lazy(() => <div>Before Lazy Layer 1<LazyInner/>After Lazy Layer 1</div>);
const e = (
<div>
<div>Before Suspense</div>
Expand Down
45 changes: 45 additions & 0 deletions test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ module.exports = {
itRenders: wrapMethod(itRenders),
itRendersWithSyncCompare: wrapMethod(itRendersWithSyncCompare),
lazy,
makeLazy,
initPromises,
removeSpacing
};

Expand Down Expand Up @@ -162,6 +164,49 @@ function lazySync(component) {
};
}

/**
* Function to make lazy component and record the promise it returns.
* @param {string} name - Name of component
* @param {Object} [options] - Options object
* @param {boolean} [noSsr=false] - If `true`, throws promise with `.noSsr` property
* @param {boolean} [noResolve=false] - If `true`, throws promise that never resolves
* @param {number} [delay=undefined] - If provided, throws promise that delays
* provided number of ms before resolving
* @param {Object} [element] - If provided, component resolves to this element,
* otherwise resolves to `<div>Lazy inner {name}</div>`
*/
let promises;
function makeLazy(name, options) {
if (!options) options = {};
let {element} = options;
if (element === undefined) element = <div>{`Lazy inner ${name}`}</div>;

let loaded = false, promise;
return function LazyComponent() {
if (loaded) return element;
if (!promise) {
if (options.noResolve) {
promise = new Promise(() => {});
} else {
promise = new Promise(resolve => {
if (options.delay != null) return setTimeout(resolve, options.delay);
resolve();
}).then(() => loaded = true);
}

if (options.noSsr) promise.noSsr = true;
promise.abort = jest.fn(); // Spy
promises[name] = promise;
}
throw promise;
};
}

function initPromises() {
promises = {};
return promises;
}

/*
* Utility functions used in individual tests
*/
Expand Down

0 comments on commit c908432

Please sign in to comment.