26 captures
08 Dec 2018 - 26 Dec 2023
Feb MAR Apr
01
2020 2021 2022
success
fail

About this capture

COLLECTED BY

Organization: Archive Team

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.

History is littered with hundreds of conflicts over the future of a community, group, location or business that were "resolved" when one of the parties stepped ahead and destroyed what was there. With the original point of contention destroyed, the debates would fall to the wayside. Archive Team believes that by duplicated condemned data, the conversation and debate can continue, as well as the richness and insight gained by keeping the materials. Our projects have ranged in size from a single volunteer downloading the data to a small-but-critical site, to over 100 volunteers stepping forward to acquire terabytes of user-created data to save for future generations.

The main site for Archive Team is at archiveteam.org and contains up to the date information on various projects, manifestos, plans and walkthroughs.

This collection contains the output of many Archive Team projects, both ongoing and completed. Thanks to the generous providing of disk space by the Internet Archive, multi-terabyte datasets can be made available, as well as in use by the Wayback Machine, providing a path back to lost websites and work.

Our collection has grown to the point of having sub-collections for the type of data we acquire. If you are seeking to browse the contents of these collections, the Wayback Machine is the best first stop. Otherwise, you are free to dig into the stacks to see what you may find.

The Archive Team Panic Downloads are full pulldowns of currently extant websites, meant to serve as emergency backups for needed sites that are in danger of closing, or which will be missed dearly if suddenly lost due to hard drive crashes or server failures.

Collection: Archive Team: URLs

TIMESTAMPS

The Wayback Machine - http://web.archive.org/web/20210301225318/https://react-testing-examples.com/jest-rtl/
 

React Testing Examples

react-testing-library
GitHubAbout

  
All examples 
Minimal setup required to use react-testing-library with Jest.
All examples featured here run using these exact config files.
jest.config.js
module.exports = {
setupFilesAfterEnv: ['./rtl.setup.js']
};
module.exports = {
  setupFilesAfterEnv: ['./rtl.setup.js']
};

rtl.setup.js
// See https://github.com/kentcdodds/react-testing-library#global-config
import 'jest-dom/extend-expect';
import 'react-testing-library/cleanup-after-each';
// See https://github.com/kentcdodds/react-testing-library#global-config
import 'jest-dom/extend-expect';
import 'react-testing-library/cleanup-after-each';

The component renders variable text based on a string prop. We test that the component renders the value of the passed prop.
test.js

it('renders personalized greeting', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = render(<HelloMessage name="Satoshi" />);
await waitForElement(() => getByText(/hello Satoshi/i));
});
it('renders personalized greeting', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = render(<HelloMessage name="Satoshi" />);

  await waitForElement(() => getByText(/hello Satoshi/i));
});

The component receives a callback prop and renders a button. We test that the callback prop is called when the button is clicked.
test.js

it('calls "onClick" prop on button click', () => {
// Render new instance in every test to prevent leaking state
const onClick = jest.fn();
const { getByText } = render(<Button onClick={onClick} />);
fireEvent.click(getByText(/click me nao/i));
expect(onClick).toHaveBeenCalled();
});
it('calls "onClick" prop on button click', () => {
  // Render new instance in every test to prevent leaking state
  const onClick = jest.fn();
  const { getByText } = render(<Button onClick={onClick} />);

  fireEvent.click(getByText(/click me nao/i));
  expect(onClick).toHaveBeenCalled();
});

The component reads and updates a counter from its local state.
We test that the component renders the counter value. Then we click on the increment button, which updates the local state, and afterwards test that the component renders the incremented value.
We use @react-mock/state to mock the component state.
test.js

// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ count }) =>
render(
<StateMock state={{ count }}>
<StatefulCounter />
</StateMock>
);
it('renders initial count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
await waitForElement(() => getByText(/clicked 5 times/i));
});
it('increments count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
fireEvent.click(getByText('+1'));
await waitForElement(() => getByText(/clicked 6 times/i));
});
// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ count }) =>
  render(
    <StateMock state={{ count }}>
      <StatefulCounter />
    </StateMock>
  );

it('renders initial count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  await waitForElement(() => getByText(/clicked 5 times/i));
});

it('increments count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  fireEvent.click(getByText('+1'));
  await waitForElement(() => getByText(/clicked 6 times/i));
});

The component reads and updates a counter from the Redux store.
We test that the component renders the counter value. Then we click on the increment button, which updates the Redux state, and afterwards test that the component renders the incremented value.
test.js

// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ count }) =>
render(
<Provider store={createStore(counterReducer, { count })}>
<ReduxCounter />
</Provider>
);
it('renders initial count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
await waitForElement(() => getByText(/clicked 5 times/i));
});
it('increments count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
fireEvent.click(getByText('+1'));
await waitForElement(() => getByText(/clicked 6 times/i));
});
// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ count }) =>
  render(
    <Provider store={createStore(counterReducer, { count })}>
      <ReduxCounter />
    </Provider>
  );

it('renders initial count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  await waitForElement(() => getByText(/clicked 5 times/i));
});

it('increments count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  fireEvent.click(getByText('+1'));
  await waitForElement(() => getByText(/clicked 6 times/i));
});

The component is connected to React Router. It renders a variable text containing a URL parameter, as well as a Link to another location.
First we make sure the component renders a param from the initial URL. Then we check that the URL param from a new location is rendered upon clicking on the Link element, which proves that the page has successfully routed.
Alternatively, we could just test the toprop of the Link element. That's also fine. But this test is closer to how a user thinks: Click on a link. Did the linked page open?
This type of thinking makes tests more resilient against implementation changes, like upgrading the router library to a new API.
test.js

// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ userId }) =>
render(
<MemoryRouter initialEntries={[`/users/${userId}`]}>
<Route path="/users/:userId">
<UserWithRouter />
</Route>
</MemoryRouter>
);
it('renders initial user id', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ userId: 5 });
await waitForElement(() => getByText(/user #5/i));
});
it('renders next user id', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ userId: 5 });
fireEvent.click(getByText(/next user/i));
await waitForElement(() => getByText(/user #6/i));
});
// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ userId }) =>
  render(
    <MemoryRouter initialEntries={[`/users/${userId}`]}>
      <Route path="/users/:userId">
        <UserWithRouter />
      </Route>
    </MemoryRouter>
  );

it('renders initial user id', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ userId: 5 });

  await waitForElement(() => getByText(/user #5/i));
});

it('renders next user id', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ userId: 5 });

  fireEvent.click(getByText(/next user/i));
  await waitForElement(() => getByText(/user #6/i));
});

The component reads and updates a server counter using the Fetch API.
We test that the component renders the counter value from the mocked API response. Then we click on the increment button, which makes a POST request to increment the counter, and afterwards test that the component renders the incremented value.
These tests are async because server requests don't resolve immediately. We wait for the button to appear before interacting with our component.
We use @react-mock/fetch to mock the server requests.
test.js

// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ count }) =>
render(
<FetchMock
mocks={[
{ matcher: '/count', method: 'GET', response: { count } },
{ matcher: '/count', method: 'POST', response: { count: count + 1 } }
]}
>
<ServerCounter />
</FetchMock>
);
it('renders initial count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
// It takes time for the counter to appear because
// the GET request has a slight delay
await waitForElement(() => getByText(/clicked 5 times/i));
});
it('increments count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
// It takes time for the button to appear because
// the GET request has a slight delay
await waitForElement(() => getByText('+1'));
fireEvent.click(getByText('+1'));
// The counter doesn't update immediately because
// the POST request is asynchronous
await waitForElement(() => getByText(/clicked 6 times/i));
});
// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ count }) =>
  render(
    <FetchMock
      mocks={[
        { matcher: '/count', method: 'GET', response: { count } },
        { matcher: '/count', method: 'POST', response: { count: count + 1 } }
      ]}
    >
      <ServerCounter />
    </FetchMock>
  );

it('renders initial count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  // It takes time for the counter to appear because
  // the GET request has a slight delay
  await waitForElement(() => getByText(/clicked 5 times/i));
});

it('increments count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  // It takes time for the button to appear because
  // the GET request has a slight delay
  await waitForElement(() => getByText('+1'));
  fireEvent.click(getByText('+1'));

  // The counter doesn't update immediately because
  // the POST request is asynchronous
  await waitForElement(() => getByText(/clicked 6 times/i));
});

The component reads and updates a server counter using the XHR API.
We test that the component renders the counter value from the mocked API response. Then we click on the increment button, which makes a POST request to increment the counter, and afterwards test that the component renders the incremented value.
These tests are async because server requests don't resolve immediately. We wait for the button to appear before interacting with our component.
We use @react-mock/xhr to mock the server requests.
test.js

// Hoist helper functions (but not vars) to reuse between test cases
const getRes = count => async (req, res) => res.status(200).body({ count });
const postRes = count => (req, res) =>
res.status(200).body({ count: count + 1 });
const renderComponent = ({ count }) =>
render(
<XhrMock
mocks={[
{ url: '/count', method: 'GET', response: getRes(count) },
{ url: '/count', method: 'POST', response: postRes(count) }
]}
>
<ServerCounter />
</XhrMock>
);
it('renders initial count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
// It takes time for the counter to appear because
// the GET request has a slight delay
await waitForElement(() => getByText(/clicked 5 times/i));
});
it('increments count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
// It takes time for the button to appear because
// the GET request has a slight delay
await waitForElement(() => getByText('+1'));
fireEvent.click(getByText('+1'));
// The counter doesn't update immediately because
// the POST request is asynchronous
await waitForElement(() => getByText(/clicked 6 times/i));
});
// Hoist helper functions (but not vars) to reuse between test cases
const getRes = count => async (req, res) => res.status(200).body({ count });

const postRes = count => (req, res) =>
  res.status(200).body({ count: count + 1 });

const renderComponent = ({ count }) =>
  render(
    <XhrMock
      mocks={[
        { url: '/count', method: 'GET', response: getRes(count) },
        { url: '/count', method: 'POST', response: postRes(count) }
      ]}
    >
      <ServerCounter />
    </XhrMock>
  );

it('renders initial count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  // It takes time for the counter to appear because
  // the GET request has a slight delay
  await waitForElement(() => getByText(/clicked 5 times/i));
});

it('increments count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  // It takes time for the button to appear because
  // the GET request has a slight delay
  await waitForElement(() => getByText('+1'));
  fireEvent.click(getByText('+1'));

  // The counter doesn't update immediately because
  // the POST request is asynchronous
  await waitForElement(() => getByText(/clicked 6 times/i));
});

The component reads and updates a value from LocalStorage.
We test that the component renders the mocked value from LocalStorage. Then we type a new name into an input, submit the form, and test that the submitted value has been updated in LocalStorage.
We use @react-mock/localstorage to mock the cached data.
test.js

// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ name }) =>
render(
<LocalStorageMock items={{ name }}>
<PersistentForm />
</LocalStorageMock>
);
const submitForm = ({ getByText, getByLabelText }, { name }) => {
fireEvent.change(getByLabelText('Name'), { target: { value: name } });
fireEvent.click(getByText(/change name/i));
};
it('renders cached name', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ name: 'Trent' });
await waitForElement(() => getByText(/welcome, Trent/i));
});
describe('on update', () => {
it('renders updated name', async () => {
// Render new instance in every test to prevent leaking state
const utils = renderComponent({ name: 'Trent' });
submitForm(utils, { name: 'Trevor' });
await waitForElement(() => utils.getByText(/welcome, Trevor/i));
});
it('updates LocalStorage cache', () => {
// Render new instance in every test to prevent leaking state
const utils = renderComponent({ name: 'Trent' });
submitForm(utils, { name: 'Trevor' });
expect(localStorage.getItem('name')).toBe('Trevor');
});
});
// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ name }) =>
  render(
    <LocalStorageMock items={{ name }}>
      <PersistentForm />
    </LocalStorageMock>
  );

const submitForm = ({ getByText, getByLabelText }, { name }) => {
  fireEvent.change(getByLabelText('Name'), { target: { value: name } });
  fireEvent.click(getByText(/change name/i));
};

it('renders cached name', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ name: 'Trent' });

  await waitForElement(() => getByText(/welcome, Trent/i));
});

describe('on update', () => {
  it('renders updated name', async () => {
    // Render new instance in every test to prevent leaking state
    const utils = renderComponent({ name: 'Trent' });
    submitForm(utils, { name: 'Trevor' });

    await waitForElement(() => utils.getByText(/welcome, Trevor/i));
  });

  it('updates LocalStorage cache', () => {
    // Render new instance in every test to prevent leaking state
    const utils = renderComponent({ name: 'Trent' });
    submitForm(utils, { name: 'Trevor' });

    expect(localStorage.getItem('name')).toBe('Trevor');
  });
});

The component is styled using styled-components themes. This means the component requires ThemeProvider context.
We're not testing style output here. The purpose of this test is merely to illustrate how to use ThemeProvider in tests.
test.js

// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ theme, name }) =>
render(
<ThemeProvider theme={theme}>
<HelloMessageStyled name={name} />
</ThemeProvider>
);
it('renders greeting', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ theme: themeLight, name: 'Maggie' });
await waitForElement(() => getByText(/hello Maggie/i));
});
// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ theme, name }) =>
  render(
    <ThemeProvider theme={theme}>
      <HelloMessageStyled name={name} />
    </ThemeProvider>
  );

it('renders greeting', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ theme: themeLight, name: 'Maggie' });

  await waitForElement(() => getByText(/hello Maggie/i));
});

Tests powered by Jest react-mock Enzyme react-testing-library and @bigtest/interactor. Website powered by Babel Cosmos MDX Next.js Prism styled-components webpack and many more.
Finally, React makes it all possible!
Made with love by Ovidiu