@testing-library/react#within JavaScript Examples

The following examples show how to use @testing-library/react#within. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: App.test.js    From HackerRank-React-Basic with MIT License 6 votes vote down vote up
expectArticles = (articles, expectedArticles) => {
  expect(articles).toHaveLength(expectedArticles.length);
  articles.forEach((article, i) => {
    const title = within(article).getByTestId("article-title").textContent;
    const upvotes = within(article).getByTestId("article-upvotes").textContent;
    const date = within(article).getByTestId("article-date").textContent;
    const expectedArticle = expectedArticles[i];
    expect([title, upvotes, date]).toEqual([expectedArticle.title, expectedArticle.upvotes.toString(), expectedArticle.date]);
  });
}
Example #2
Source File: swap_card.spec.js    From astroport-lbp-frontend with MIT License 6 votes vote down vote up
async function waitForBalances({ fromBalance, toBalance }) {
  const [fromBalanceLabel, toBalanceLabel] = screen.getAllByText('Balance:');

  if(fromBalance !== undefined) {
    expect(await within(fromBalanceLabel.parentElement).findByText(fromBalance)).toBeInTheDocument();
  }

  if(toBalance !== undefined) {
    expect(await within(toBalanceLabel.parentElement).findByText(toBalance)).toBeInTheDocument();
  }
}
Example #3
Source File: Pagination.test.js    From react-dsfr with MIT License 6 votes vote down vote up
describe('<Pagination />', () => {
  it('should render pagination properly', () => {
    render(
      <Pagination buildURL={(page) => `page${page}`} currentPage={8} pageCount={15} data-testid="pagination" />,
    );
    const pagination = screen.getByTestId('pagination');
    expect(pagination.className).toBe('fr-pagination');
    const pages = screen.getByRole('list');
    const { getAllByRole } = within(pages);
    const items = getAllByRole('listitem');
    expect(items.length).toBe(13);
    expect(pagination).toMatchSnapshot();
  });

  it('should render state pagination properly', () => {
    render(
      <Pagination onClick={() => {}} currentPage={8} pageCount={15} data-testid="pagination" />,
    );
    const pagination = screen.getByTestId('pagination');
    expect(pagination.className).toBe('fr-pagination');
    const pages = screen.getByRole('list');
    const { getAllByRole } = within(pages);
    const items = getAllByRole('listitem');
    expect(items.length).toBe(13);
    expect(pagination).toMatchSnapshot();
  });
});
Example #4
Source File: Skiplinks.test.js    From react-dsfr with MIT License 6 votes vote down vote up
describe('<SkipLinks />', () => {
  it('should renders SkipLinks properly', () => {
    render(
      <Skiplinks data-testid="skiplinks">
        <SkiplinkItem href="#" data-testid="skiplinkitem1">Accéder au contenu</SkiplinkItem>
        <SkiplinkItem href="#" data-test-id="skiplinkitem2">Accéder au menu</SkiplinkItem>
        <SkiplinkItem href="#" data-test--id="skiplinkitem3">Accéder à la recherche</SkiplinkItem>
        <SkiplinkItem href="#" data-test="skiplinkitem4">Accéder au footer</SkiplinkItem>
      </Skiplinks>,
    );
    const skiplinks = screen.getByTestId('skiplinks');
    expect(skiplinks).toBeInTheDocument();
    expect(skiplinks).toMatchSnapshot();
    const links = screen.getByRole('list');
    const { getAllByRole } = within(links);
    const items = getAllByRole('listitem');
    expect(items.length).toBe(4);
  });
});
Example #5
Source File: Provider.test.jsx    From covid with GNU General Public License v3.0 6 votes vote down vote up
test('a multiple context consumer is rendered properly when rendered inside the multi-provider', async () => {
  const rendered = render(
    <Provider>
      <WrappedChild data-value='test-props' />
    </Provider>
  )
  const child = rendered.getByRole('child')
  expect(child).toBeInTheDocument();

  ['Bcn', 'Map', 'Chart'].forEach((backend) => {
    const testBackend = within(child).getByRole(backend)
    expect(testBackend).toHaveTextContent(`class ${backend}DataHandler`)
  })
})
Example #6
Source File: setup.js    From ui-data-export with Apache License 2.0 6 votes vote down vote up
checkJobProfileFormState = async (form, { title }) => {
  const formTitle = await within(form).findByText(title);
  const nameInput = await within(form).findByLabelText(/Name/i);
  const mappingProfileInput = await within(form).findByLabelText(/Mapping profile/i);
  const descriptionInput = await within(form).findByLabelText('Description');

  expect(form).toBeVisible();
  expect(formTitle).toBeVisible();
  expect(nameInput).toBeVisible();
  expect(mappingProfileInput).toBeVisible();

  expect(descriptionInput).toBeVisible();

  expect(nameInput).toBeEnabled();
  expect(descriptionInput).toBeEnabled();
  expect(mappingProfileInput).toBeEnabled();

  return {
    formTitle,
    nameInput,
    mappingProfileInput,
    descriptionInput,
  };
}
Example #7
Source File: worldwide.spec.js    From horondi_admin with MIT License 6 votes vote down vote up
describe('tests for worldwide delivery component', () => {
  it('worldwide delivery component should be rendered correctly', () => {
    render(<Worldwide {...props} setFieldValue={setFieldValue} />);

    const heading = screen.getByRole('heading', { level: 3 });

    const statesWrapper = screen.getByTestId('stateOrProvince');
    const statesInput = within(statesWrapper).getByRole('textbox');

    expect(heading).toBeInTheDocument();
    expect(statesInput).toHaveAttribute('disabled');
  });

  it('test typing in worldwideCity input', () => {
    render(
      <Worldwide
        {...props}
        values={{ worldWideCountry: 'Ukraine' }}
        setFieldValue={setFieldValue}
      />
    );

    const citiesWrapper = screen.getByTestId('worldWideCity');
    const citiesInput = within(citiesWrapper).getByRole('textbox');

    fireEvent.change(citiesInput, { target: { value: 'city' } });
    expect(citiesInput).toHaveAttribute('value', 'city');
  });
});
Example #8
Source File: delivery.spec.js    From horondi_admin with MIT License 6 votes vote down vote up
describe('tests for delivery component', () => {
  it('should render delivery component with worldwide fields', () => {
    render(
      <Delivery
        setFieldValue={setFieldValue}
        data={{ delivery: { ...deliveryProps, sentBy: 'WORLDWIDE' } }}
      />
    );

    const statesWrapper = screen.getByTestId('stateOrProvince');
    const statesInput = within(statesWrapper).getByRole('textbox');

    expect(statesInput).toHaveAttribute('disabled');
  });

  it('should render delivery component with ukrpost courier or novapost courier fields', () => {
    render(
      <Delivery
        setFieldValue={setFieldValue}
        data={{ delivery: { ...deliveryProps, sentBy: 'UKRPOSTCOURIER' } }}
      />
    );

    const cityInputWrapper = screen.getByTestId('delivery.courier.city');
    const cityInput = within(cityInputWrapper).getByRole('textbox');

    expect(cityInput).toBeInTheDocument();
  });
});
Example #9
Source File: worldwide.spec.js    From horondi_client_fe with MIT License 6 votes vote down vote up
describe('tests for worldwide delivery component', () => {
  it('worldwide delivery component should be rendered correctly', () => {
    render(<Worldwide {...props} />);

    const heading = screen.getByRole('heading', { level: 3 });

    const statesWrapper = screen.getByTestId('stateOrProvince');
    const statesInput = within(statesWrapper).getByRole('textbox');

    expect(heading).toBeInTheDocument();
    expect(statesInput).toHaveAttribute('disabled');
  });

  it('test typing in worldwideCity input', () => {
    render(<Worldwide {...props} values={{ worldWideCountry: 'Ukraine' }} />);

    const citiesWrapper = screen.getByTestId('worldWideCity');
    const citiesInput = within(citiesWrapper).getByRole('textbox');

    fireEvent.change(citiesInput, { target: { value: 'city' } });
    expect(citiesInput).toHaveAttribute('value', 'city');
  });
});
Example #10
Source File: delivery-type.test.js    From horondi_client_fe with MIT License 6 votes vote down vote up
describe('<DeliveryType />', () => {
  it('Radio group should be rendered', () => {
    render(<DeliveryType {...props} deliveryType='COURIER' />);

    const radiogroup = screen.getByRole('radiogroup', { name: 'Delivery type' });
    expect(radiogroup).toBeInTheDocument();
  });

  it('setDeliveryType function should be called with correct argument', () => {
    render(<DeliveryType {...props} deliveryType='NOVAPOST' />);

    expect(props.setDeliveryType).toHaveBeenCalledWith('NOVAPOST');
  });

  it('handleCourierOrganizationChange function should triggered on select change', () => {
    render(<DeliveryType {...props} deliveryType='COURIER' />);

    const selectWrapper = screen.getByTestId('courierOrganization');
    const selectComponent = within(selectWrapper).getByRole('button');

    fireEvent.mouseDown(selectComponent);

    const popup = within(screen.getByRole('listbox'));

    fireEvent.click(popup.getAllByRole('option')[0]);
  });
});
Example #11
Source File: testingUtility.js    From lens-extension-cc with MIT License 5 votes vote down vote up
customWithin = function (el) {
  const result = within(el);
  const boundQueries = getBoundQueries(el);
  return { ...result, ...boundQueries };
}
Example #12
Source File: current_token_sale.spec.js    From astroport-lbp-frontend with MIT License 5 votes vote down vote up
describe('CurrentTokenSale', () => {
  it('fetches and displays data for current token sale', async () => {
    fetchUSTExchangeRate.mockResolvedValue(0.99);
    getWeights.mockResolvedValue([5, 95]);
    getPool.mockResolvedValue({
      assets: [
        {
          info: {
            native_token: {
              denom: 'uusd'
            }
          },
          amount: '5000000000000', // 5,000,000.000000
          start_weight: '2',
          end_weight: '60'
        },
        {
          info: {
            token: {
              contract_addr: 'terra123'
            }
          },
          amount: '42000000123456', // 42,000,000.123456
          start_weight: '98',
          end_weight: '40'
        }
      ],
      total_share: '60000000'
    });

    const pair = buildPair({
      contractAddr: 'terra1',
      tokenContractAddr: 'terra123',
      endTime: Math.floor((new Date(2021, 5, 18, 11, 10)).getTime() / 1000),
      description: 'A brand new token for sale!'
    });

    const saleTokenInfo = {
      symbol: 'FOO',
      decimals: 6
    };

    const dateNowSpy = jest
      .spyOn(Date, 'now')
      .mockImplementation(() => new Date(2021, 5, 16, 8).getTime());

    render(<CurrentTokenSale pair={pair} saleTokenInfo={saleTokenInfo} />);

    const priceCard = (await screen.findByText('Price')).closest('div');
    const coinsRemainingCard = (await screen.findByText('Coins Remaining')).closest('div');
    const timeRemainingCard = (await screen.findByText('Time Remaining')).closest('div');
    const currentWeightCard = (await screen.findByText('Current Weight')).closest('div');
    const aboutCard = (await screen.findByText('About')).closest('div');

    // ((500000000000 / 5) / (42000000123456 / 95)) = 2.261904755 * $0.99 = $2.239285714
    expect(within(priceCard).getByText('$2.24')).toBeInTheDocument();

    expect(within(coinsRemainingCard).getByText('42,000,000.123456')).toBeInTheDocument();

    // 2021-06-16 @ 8am -> 2021-06-18 @ 11:10am
    expect(within(timeRemainingCard).getByText('2d : 3h : 10m')).toBeInTheDocument();

    expect(within(currentWeightCard).getByText('5 : 95')).toBeInTheDocument();

    expect(within(aboutCard).getByText('A brand new token for sale!')).toBeInTheDocument();

    expect(getWeights).toHaveBeenCalledWith(mockTerraClient, 'terra1', 'uusd');
    expect(getPool).toHaveBeenCalledWith(mockTerraClient, 'terra1');

    dateNowSpy.mockRestore();
  });
});
Example #13
Source File: setup.js    From ui-data-export with Apache License 2.0 5 votes vote down vote up
transformationListCells = () => within(transformationListRows()[0]).getByText('Instance - Resource title')
Example #14
Source File: CaptureTable.test.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('Captures', () => {
  let component;
  let data = CAPTURES;

  // mock the treeTrackerApi
  const captureApi = require('../../api/treeTrackerApi').default;

  captureApi.getCaptureTags = () => {
    log.debug(`mock getCaptureTags: ${CAPTURE_TAGS}`);
    return Promise.resolve(CAPTURE_TAGS);
  };

  describe('CapturesTable renders properly', () => {
    beforeEach(async () => {
      component = (
        <ThemeProvider theme={theme}>
          <CapturesContext.Provider value={capturesValues}>
            <SpeciesContext.Provider value={speciesValues}>
              <TagsContext.Provider value={tagsValues}>
                <CaptureTable />
              </TagsContext.Provider>
            </SpeciesContext.Provider>
          </CapturesContext.Provider>
        </ThemeProvider>
      );

      render(component);
    });

    afterEach(cleanup);

    it('api loaded 4 captures', () => {
      // screen.logTestingPlaygroundURL();
      expect(capturesValues.captures).toHaveLength(4);
    });

    it('should show rows per page at top and bottom', () => {
      const pageNums = screen.getAllByRole('button', {
        name: /rows per page: 25/i,
      });
      expect(pageNums).toHaveLength(2);
    });

    it('should show page # and capture count', () => {
      const counts = Array.from(
        document.querySelectorAll('.MuiTablePagination-caption')
      );
      const arr = counts.map((count) => count.firstChild.textContent);
      expect(arr[1]).toBe('1-4 of 4');
    });

    it('should have 10 headers', () => {
      const table = screen.getByRole(/table/i);
      const headers = within(table).getAllByRole(/columnheader/i);
      const arr = headers.map((header) => header.textContent);
      expect(arr).toHaveLength(10);
    });

    it('renders headers for captures table', () => {
      const table = screen.getByRole(/table/i);
      let item = screen.getAllByText(/Captures/i)[0];
      expect(item).toBeInTheDocument();
      item = within(table).getByText(/Capture ID/i);
      expect(item).toBeInTheDocument();
      item = within(table).getByText(/Grower ID/i);
      expect(item).toBeInTheDocument();
      item = within(table).getByText(/Device Identifier/i);
      expect(item).toBeInTheDocument();
      item = within(table).getByText(/Planter Identifier/i);
      expect(item).toBeInTheDocument();
      item = within(table).getByText(/Verification Status/i);
      expect(item).toBeInTheDocument();
      item = within(table).getByText(/Species/i);
      expect(item).toBeInTheDocument();
      item = within(table).getByText(/Token Id/i);
      expect(item).toBeInTheDocument();
      item = within(table).getByText(/Capture Tags/i);
      expect(item).toBeInTheDocument();
      item = within(table).getByText(/Created/i);
      expect(item).toBeInTheDocument();
    });

    it('renders 4 rows ', () => {
      const table = screen.getAllByRole(/rowgroup/i);
      const rows = within(table[1]).getAllByRole(/row/i);
      const arr = rows.map((link) => link.textContent);
      expect(rows).toHaveLength(4);
    });

    it('renders links for planter ids (10-12)', () => {
      const table = screen.getByTestId('captures-table-body');
      const links = within(table).getAllByRole('link');
      const arr = links.map((link) => link.textContent);
      expect(arr.includes('10')).toBeTruthy();
      expect(arr.includes('11')).toBeTruthy();
      expect(arr.includes('12')).toBeTruthy();
    });

    it('displays captures data', () => {
      const table = screen.getByTestId('captures-table-body');
      const status = within(table).getAllByText(/approved/i);
      expect(status).toHaveLength(2);
      const device = within(table).getAllByText(/1-abcdef123456/i);
      expect(device).toHaveLength(1);
      const captureTag = within(table).getAllByText(/tag_c/i);
      expect(captureTag).toHaveLength(4);
    });
  });

  describe.skip('makes api requests correctly', () => {
    const context = {
      isLoading: true,
      captures: [],
      captureCount: 4,
      selected: [],
      capture: {},
      numSelected: 0,
      page: 0,
      rowsPerPage: 25,
      order: 'asc',
      orderBy: 'id',
      allIds: [],
      byId: {},
      filter: new FilterModel(),
      // queryCapturesApi: jest.fn(),
      queryCapturesApi: () => {},
      getCaptureCount: () => {},
      getCapturesAsync: () => {},
      getCaptureAsync: () => {},
    };

    // Mock the API

    // WORKS TO MAKE REQUESTS
    // axios.get
    //   .mockReturnValueOnce({
    //     data: { count: data.length },
    //   })
    //   .mockReturnValueOnce({ data });

    // PASSES TESTS BUT STILL DOESN'T RETURN DATA
    context.queryCapturesApi = jest.fn(() => {
      console.log('mock queryCapturesApi');
      // return Promise.resolve({ data });
      return axios.get
        .mockReturnValueOnce({
          data: { count: data.length },
        })
        .mockReturnValueOnce({ data });
    });

    context.queryCapturesApi = jest.fn(() => {
      console.log('mock queryCapturesApi');
      // return Promise.resolve({ data });
      return axios.get
        .mockReturnValueOnce({
          data: { count: data.length },
        })
        .mockReturnValueOnce({ data });
    });

    beforeEach(async () => {
      component = (
        <ThemeProvider theme={theme}>
          <CapturesProvider value={context}>
            <CaptureTable />
          </CapturesProvider>
        </ThemeProvider>
      );

      render(component);
      act(() => axios.get());
      act(() => context.queryCapturesApi()); //passes tests
      // await act(async () => await context.queryCapturesApi()); //stops data errors
    });

    afterEach(cleanup);

    it('should make a request for capture count', () => {
      expect(axios.get).toHaveBeenCalled();
      // console.log(axios.get.mock.calls);
      expect(axios.get.mock.calls[1][0]).toContain(`trees/count?`);
    });

    it('should call captures API with a valid filter', () => {
      const filter = JSON.stringify({
        where: { approved: true, active: true },
        order: ['id asc'],
        limit: 25,
        skip: 0,
        fields: {
          id: true,
          timeCreated: true,
          status: true,
          active: true,
          approved: true,
          planterId: true,
          planterIdentifier: true,
          deviceIdentifier: true,
          speciesId: true,
          tokenId: true,
        },
      });

      expect(axios.get).toHaveBeenCalled();
      expect(axios.get.mock.calls[0][0]).toContain(`/trees?filter=${filter}`);
    });
  });
});
Example #15
Source File: CaptureFilter.test.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('CaptureFilter organizations', () => {
  const api = require('../../api/treeTrackerApi').default;
  beforeEach(() => {
    //mock the api

    api.getOrganizations = () => {
      // log.debug('mock getOrganizations:');
      return Promise.resolve(ORGS);
    };
  });

  describe('CaptureFilter', () => {
    describe('w/o data in context', () => {
      beforeEach(async () => {
        render(
          <AppProvider>
            <CaptureFilter />
          </AppProvider>
        );
      });

      afterEach(cleanup);

      it('renders text "Verification Status" ', () => {
        expect(screen.getByText('Verification Status')).toBeInTheDocument();
      });

      it('renders "Start Date" input ', () => {
        const input = screen.getByRole('textbox', { name: 'Start Date' });
        expect(input).toBeInTheDocument();
      });

      it('renders "End Date" input ', () => {
        const input = screen.getByRole('textbox', { name: 'End Date' });
        expect(input).toBeInTheDocument();
      });

      it('renders Species dropdown ', () => {
        const dropdown = screen.getByTestId('species-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders Tags dropdown ', () => {
        const dropdown = screen.getByTestId('tag-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders Organization dropdown ', () => {
        const dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders default orgList when dropdown clicked ', () => {
        const dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();

        const button = within(dropdown).getByRole('button', {
          name: /all/i,
        });

        userEvent.click(button);

        // the actual list of orgs is displayed in a popup that is not part of CaptureFilter
        // this list is the default list
        const orglist = screen.getByRole('listbox');
        const orgs = within(orglist).getAllByTestId('org-item');
        const listItems = orgs.map((org) => org.textContent);
        console.log('default orgList', listItems);

        expect(orgs).toHaveLength(2);
      });
    });

    describe('w/ data in context', () => {
      let orgs;

      beforeEach(async () => {
        orgs = await api.getOrganizations();

        render(
          <AppProvider value={{ orgList: orgs }}>
            <CaptureFilter />
          </AppProvider>
        );
        await act(() => api.getOrganizations());
      });

      afterEach(cleanup);

      it('api loaded 2 organizations', () => {
        expect(orgs).toHaveLength(2);
      });

      it('renders Organization dropdown ', () => {
        const dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders default orgList when dropdown clicked ', () => {
        const dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();

        const button = within(dropdown).getByRole('button', { name: /all/i });

        userEvent.click(button);

        // screen.logTestingPlaygroundURL();

        // the actual list of orgs is displayed in a popup that is not part of CaptureFilter
        const orglist = screen.getByRole('listbox');
        const orgs = within(orglist).getAllByTestId('org-item');
        const listItems = orgs.map((org) => org.textContent);
        console.log('default orgList', listItems);

        // two default options + two orgs
        expect(orgs).toHaveLength(4);
      });
    });

    describe.skip('context data renders in child', () => {
      beforeEach(async () => {
        render(
          <AppProvider>
            <AppContext.Consumer>
              {(value) => <p>Received: {value.orgList}</p>}
            </AppContext.Consumer>
          </AppProvider>
        );

        await act(() => api.getOrganizations());
      });

      // just tests the mock api, not what's showing on the page
      it('api loaded 2 organizations', () => {
        expect(orgs).toHaveLength(2);
      });

      it('renders text "Dummy Org" ', () => {
        // screen.debug(); // shows structure in console
        screen.logTestingPlaygroundURL();
        // expect(screen.getByText(/^Received:/).textContent).toBe('Received: ');
        expect(screen.getByText('Dummy Org')).toBeInTheDocument();
      });
    });
  });
});
Example #16
Source File: FilterTop.test.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('FilterTop organizations', () => {
  let api;

  beforeEach(() => {
    //mock the api
    api = require('../../api/treeTrackerApi').default;

    api.getOrganizations = () => {
      // log.debug('mock getOrganizations:');
      return Promise.resolve(ORGS);
    };
  });

  describe('FilterTop', () => {
    describe('w/o data in context', () => {
      let component;

      beforeEach(async () => {
        component = (
          <AppProvider>
            <FilterTop />
          </AppProvider>
        );
      });

      afterEach(cleanup);

      it('renders without crashing', () => {
        const div = document.createElement('div');
        ReactDOM.render(component, div);
        ReactDOM.unmountComponentAtNode(div);
      });

      it('renders text "Verification Status" ', () => {
        render(component);
        expect(screen.getByText('Verification Status')).toBeInTheDocument();
      });

      it('renders "Start Date" input ', () => {
        render(component);
        let input = screen.getByRole('textbox', { name: 'Start Date' });
        expect(input).toBeInTheDocument();
      });

      it('renders "End Date" input ', () => {
        render(component);
        let input = screen.getByRole('textbox', { name: 'End Date' });
        expect(input).toBeInTheDocument();
      });

      it('renders Species dropdown ', () => {
        render(component);
        let dropdown = screen.getByTestId('species-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders Tags dropdown ', () => {
        render(component);
        let dropdown = screen.getByTestId('tag-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders Organization dropdown ', () => {
        render(component);
        let dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders default orgList when dropdown clicked ', () => {
        render(component);
        let dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();

        let button = within(dropdown).getByRole('button', {
          name: /all/i,
        });

        userEvent.click(button);

        // the actual list of orgs is displayed in a popup that is not part of FilterTop
        // this list is the default list
        const orglist = screen.getByRole('listbox');
        const orgs = within(orglist).getAllByTestId('org-item');
        const listItems = orgs.map((org) => org.textContent);
        console.log('default orgList', listItems);

        expect(orgs).toHaveLength(2);
      });
    });

    describe('w/ data in context', () => {
      let orgs;
      let component;

      beforeEach(async () => {
        orgs = await api.getOrganizations();
        component = (
          <AppProvider value={{ orgList: orgs }}>
            <FilterTop />
          </AppProvider>
        );
        // render(component);
        await act(() => api.getOrganizations());
      });

      afterEach(cleanup);

      it('api loaded 2 organizations', () => {
        expect(orgs).toHaveLength(2);
      });

      it('renders Organization dropdown ', () => {
        render(component);
        let dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders default orgList when dropdown clicked ', () => {
        render(component);
        let dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();

        let button = within(dropdown).getByRole('button', { name: /all/i });

        userEvent.click(button);

        // screen.logTestingPlaygroundURL();

        // the actual list of orgs is displayed in a popup that is not part of FilterTop
        const orglist = screen.getByRole('listbox');
        const orgs = within(orglist).getAllByTestId('org-item');
        const listItems = orgs.map((org) => org.textContent);
        console.log('default orgList', listItems);

        // two default options + two orgs
        expect(orgs).toHaveLength(4);
      });
    });

    // describe('context data renders in child', () => {
    //   let orgs;
    //   let component;

    //   beforeEach(async () => {
    //     component = (
    //       <AppProvider>
    //         <AppContext.Consumer>
    //           {(value) => <p>Received: {value.orgList}</p>}
    //         </AppContext.Consumer>
    //       </AppProvider>
    //     );

    //     render(component);

    //     await act(() => api.getOrganizations());
    //   });

    //   // just tests the mock api, not what's showing on the page
    //   it('api loaded 2 organizations', () => {
    //     expect(orgs).toHaveLength(2);
    //   });

    //   it('renders text "Dummy Org" ', () => {
    //     // screen.debug(); // shows structure in console
    //     screen.logTestingPlaygroundURL();
    //     // expect(screen.getByText(/^Received:/).textContent).toBe('Received: ');
    //     expect(screen.getByText('Dummy Org')).toBeInTheDocument();
    //   });
    // });
  });
});
Example #17
Source File: FilterTopGrower.test.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('growers', () => {
  let api;

  beforeEach(() => {
    //mock the api
    api = require('../../api/growers').default;

    api.getCount = () => {
      log.debug('mock getCount');
      return Promise.resolve({ count: 2 });
    };
    api.getGrower = () => {
      log.debug('mock getGrower');
      return Promise.resolve(GROWER);
    };
    api.getGrowers = () => {
      log.debug('mock load');
      return Promise.resolve(GROWERS);
    };
  });

  describe('with a default context', () => {
    beforeEach(async () => {
      render(
        <ThemeProvider theme={theme}>
          <BrowserRouter>
            <AppProvider value={{ orgList: ORGS }}>
              <GrowerProvider value={growerValues}>
                <FilterTopGrower />
              </GrowerProvider>
            </AppProvider>
          </BrowserRouter>
        </ThemeProvider>
      );

      await act(() => api.getGrowers());
      // await act(() => api.getCount());
    });

    afterEach(cleanup);

    it('renders subcomponents of filter top grower', () => {
      // screen.logTestingPlaygroundURL();
      // const filter = screen.getByRole('button', { name: /filter/i });
      // userEvent.click(filter);

      expect(screen.getByLabelText(/Grower ID/)).toBeInTheDocument();

      expect(screen.getByLabelText(/Person ID/)).toBeInTheDocument();

      expect(screen.getByLabelText(/Device ID/)).toBeInTheDocument();

      expect(screen.getByLabelText(/Organization/)).toBeInTheDocument();

      expect(screen.getByLabelText(/first name/i)).toBeInTheDocument();

      expect(screen.getByLabelText(/last name/i)).toBeInTheDocument();

      expect(screen.getByLabelText(/email/i)).toBeInTheDocument();

      expect(screen.getByLabelText(/phone number/i)).toBeInTheDocument();
    });

    it('renders Organization dropdown ', () => {
      let dropdown = screen.getByTestId('org-dropdown');
      expect(dropdown).toBeInTheDocument();
    });

    it('renders default orgList when dropdown clicked ', () => {
      let dropdown = screen.getByTestId('org-dropdown');
      expect(dropdown).toBeInTheDocument();

      // screen.logTestingPlaygroundURL(dropdown);

      let button = within(dropdown).getByRole('button', {
        name: /organization all/i,
      });

      userEvent.click(button);

      // the actual list of orgs is displayed in a popup that is not part of FilterTop
      const orglist = screen.getByRole('listbox');
      const orgs = within(orglist).getAllByTestId('org-item');
      const listItems = orgs.map((org) => org.textContent);
      console.log('default orgList', listItems);

      // two default options + two orgs
      expect(orgs).toHaveLength(4);
    });
  });
});
Example #18
Source File: organizations.test.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('CaptureFilter organizations', () => {
  let api;

  beforeEach(() => {
    //mock the api
    api = require('../../api/treeTrackerApi').default;

    api.getOrganizations = () => {
      // log.debug('mock getOrganizations:');
      return Promise.resolve(ORGS);
    };
  });

  describe('CaptureFilter', () => {
    describe('w/o data in context', () => {
      let component;

      beforeEach(async () => {
        component = (
          <AppProvider>
            <CaptureFilter />
          </AppProvider>
        );
      });

      afterEach(cleanup);

      it('renders without crashing', () => {
        const div = document.createElement('div');
        ReactDOM.render(component, div);
        ReactDOM.unmountComponentAtNode(div);
      });

      it('renders text "Verification Status" ', () => {
        render(component);
        expect(screen.getByText('Verification Status')).toBeInTheDocument();
      });

      it('renders "Start Date" input ', () => {
        render(component);
        let input = screen.getByRole('textbox', { name: 'Start Date' });
        expect(input).toBeInTheDocument();
      });

      it('renders "End Date" input ', () => {
        render(component);
        let input = screen.getByRole('textbox', { name: 'End Date' });
        expect(input).toBeInTheDocument();
      });

      it('renders Species dropdown ', () => {
        render(component);
        let dropdown = screen.getByTestId('species-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders Tags dropdown ', () => {
        render(component);
        let dropdown = screen.getByTestId('tag-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders Organization dropdown ', () => {
        render(component);
        let dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders default orgList when dropdown clicked ', () => {
        render(component);
        let dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();

        let button = within(dropdown).getByRole('button', {
          name: /all/i,
        });

        userEvent.click(button);

        // the actual list of orgs is displayed in a popup that is not part of CaptureFilter
        // this list is the default list
        const orglist = screen.getByRole('listbox');
        const orgs = within(orglist).getAllByTestId('org-item');
        const listItems = orgs.map((org) => org.textContent);
        console.log('default orgList', listItems);

        expect(orgs).toHaveLength(2);
      });
    });

    describe('w/ data in context', () => {
      let orgs;
      let component;

      beforeEach(async () => {
        orgs = await api.getOrganizations();
        component = (
          <AppProvider value={{ orgList: orgs }}>
            <CaptureFilter />
          </AppProvider>
        );
        // render(component);
        await act(() => api.getOrganizations());
      });

      afterEach(cleanup);

      it('api loaded 2 organizations', () => {
        expect(orgs).toHaveLength(2);
      });

      it('renders Organization dropdown ', () => {
        render(component);
        let dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();
      });

      it('renders default orgList when dropdown clicked ', () => {
        render(component);
        let dropdown = screen.getByTestId('org-dropdown');
        expect(dropdown).toBeInTheDocument();

        let button = within(dropdown).getByRole('button', { name: /all/i });

        userEvent.click(button);

        // screen.logTestingPlaygroundURL();

        // the actual list of orgs is displayed in a popup that is not part of CaptureFilter
        const orglist = screen.getByRole('listbox');
        const orgs = within(orglist).getAllByTestId('org-item');
        const listItems = orgs.map((org) => org.textContent);
        console.log('default orgList', listItems);

        // two default options + two orgs
        expect(orgs).toHaveLength(4);
      });
    });

    // describe('context data renders in child', () => {
    //   let orgs;
    //   let component;

    //   beforeEach(async () => {
    //     component = (
    //       <AppProvider>
    //         <AppContext.Consumer>
    //           {(value) => <p>Received: {value.orgList}</p>}
    //         </AppContext.Consumer>
    //       </AppProvider>
    //     );

    //     render(component);

    //     await act(() => api.getOrganizations());
    //   });

    //   // just tests the mock api, not what's showing on the page
    //   it('api loaded 2 organizations', () => {
    //     expect(orgs).toHaveLength(2);
    //   });

    //   it('renders text "Dummy Org" ', () => {
    //     // screen.debug(); // shows structure in console
    //     screen.logTestingPlaygroundURL();
    //     // expect(screen.getByText(/^Received:/).textContent).toBe('Received: ');
    //     expect(screen.getByText('Dummy Org')).toBeInTheDocument();
    //   });
    // });
  });
});
Example #19
Source File: regions.test.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('region management', () => {
  let treeTrackerApi;
  let regionsApi;
  let regionValues;

  beforeEach(() => {
    regionsApi = require('../../api/regions').default;
    treeTrackerApi = require('../../api/treeTrackerApi').default;

    regionsApi.getRegions = jest.fn(() => {
      return Promise.resolve({
        query: {
          count: REGIONS.length,
        },
        regions: REGIONS,
      });
    });

    regionsApi.getRegion = jest.fn((id) => {
      const region = REGIONS.find((reg) => id === reg.id);
      return Promise.resolve({ region });
    });

    regionsApi.getCollections = jest.fn(() => {
      return Promise.resolve({
        query: {
          count: REGION_COLLECTIONS.length,
        },
        collections: REGION_COLLECTIONS,
      });
    });

    regionsApi.getCollection = jest.fn((id) => {
      const collection = REGION_COLLECTIONS.find((coll) => id === coll.id);
      return Promise.resolve({ collection });
    });

    regionsApi.upload = jest.fn(() => {
      return Promise.resolve(REGIONS[0]);
    });

    regionsApi.updateRegion = jest.fn(() => {
      return Promise.resolve(REGIONS[0]);
    });

    regionsApi.updateCollection = jest.fn(() => {
      return Promise.resolve(REGION_COLLECTIONS[0]);
    });

    treeTrackerApi.getOrganizations = jest.fn(() => {
      return Promise.resolve(ORGS);
    });

    regionValues = {
      regions: REGIONS,
      collections: REGION_COLLECTIONS,
      pageSize: 25,
      regionCount: null,
      collectionCount: null,
      currentPage: 0,
      filter: new FilterRegion(),
      isLoading: false,
      showCollections: false,
      changePageSize: () => {},
      changeCurrentPage: () => {},
      changeSort: () => {},
      setShowCollections: () => {},
      loadRegions: () => {},
      loadCollections: () => {},
      getRegion: () => {},
      upload: () => {},
      updateRegion: () => {},
      updateCollection: () => {},
      updateFilter: () => {},
      deleteRegion: () => {},
      deleteCollection: () => {},
    };
  });

  afterEach(cleanup);

  describe('<Regions /> renders page', () => {
    beforeEach(async () => {
      render(
        <BrowserRouter>
          <AppProvider value={{ orgList: ORGS }}>
            <RegionProvider value={regionValues}>
              <RegionsView />
            </RegionProvider>
          </AppProvider>
        </BrowserRouter>
      );
      await act(() => regionsApi.getRegions());
    });

    afterEach(cleanup);

    describe('it shows main page elements', () => {
      it('then shows "Upload" button', () => {
        expect(screen.getByText(/Upload/i)).toBeTruthy();
      });

      it('species list should be 2', () => {
        expect(regionValues.regions).toHaveLength(2);
      });

      // shows a table with headers
      // shows navigation menu
    });

    describe('when the "Upload" button is clicked', () => {
      beforeEach(() => {
        userEvent.click(screen.getByText(/Upload/i));
      });

      it('see popup with upload region or collection form', () => {
        expect(
          screen.getByText(/Upload New Region or Collection/i)
        ).toBeTruthy();
      });

      it('has inputs for owner and region name property', () => {
        const dialog = screen.getByRole(/dialog/i);
        expect(within(dialog).getByLabelText(/owner/i)).toBeTruthy();
        expect(
          within(dialog).getByLabelText(/region name property/i)
        ).toBeTruthy();
      });

      it('has buttons to upload and cancel', () => {
        const dialog = screen.getByRole(/dialog/i);
        expect(
          within(dialog).getByRole('button', { name: /upload/i })
        ).toBeTruthy();
      });
    });

    describe('regions table', () => {
      it('shows the table header', () => {
        const table = screen.getByRole(/table/i);
        expect(within(table).getByText(/name/i)).toBeTruthy();
        expect(within(table).getByText(/owner/i)).toBeTruthy();
        expect(within(table).getByText(/collection/i)).toBeTruthy();
        expect(within(table).getByText(/properties/i)).toBeTruthy();
        expect(within(table).getByText(/shown on org map/i)).toBeTruthy();
        expect(within(table).getByText(/statistics calculated/i)).toBeTruthy();
      });

      it('shows a region record', () => {
        const table = screen.getByRole(/table/i);
        expect(within(table).getByText(REGIONS[0].name)).toBeTruthy();
        expect(within(table).getAllByText(ORGS[0].name)).toBeTruthy();
        expect(
          within(table).getAllByText(REGION_COLLECTIONS[0].name)
        ).toBeTruthy();
        expect(within(table).getByText(REGIONS[0].properties.Id)).toBeTruthy();
      });
    });
  });
});
Example #20
Source File: species.test.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('species management', () => {
  let api;
  let speciesValues;
  // can be used to test routes and permissions

  beforeEach(() => {
    api = require('../../api/treeTrackerApi').default;

    api.getSpecies = jest.fn(() => {
      // log.debug('mock getSpecies:');
      return Promise.resolve(SPECIES);
    });

    api.createSpecies = jest.fn(() => {
      // log.debug('mock createSpecies');
      return Promise.resolve({
        id: 2,
        name: 'water melon',
        desc: 'fruit',
      });
    });

    api.getCaptureCountPerSpecies = jest.fn(() => {
      return Promise.resolve({ count: (Math.random() * 10) >> 0 });
    });

    speciesValues = {
      speciesList: SPECIES,
      speciesInput: '',
      speciesDesc: '',
      setSpeciesInput: () => {},
      loadSpeciesList: () => {},
      onChange: () => {},
      isNewSpecies: () => {},
      createSpecies: () => {},
      getSpeciesId: () => {},
      editSpecies: () => {},
      deleteSpecies: () => {},
      combineSpecies: () => {},
    };
  });

  afterEach(cleanup);

  describe('<SpeciesView /> renders page', () => {
    beforeEach(async () => {
      render(
        <BrowserRouter>
          <AppProvider>
            <SpeciesProvider value={speciesValues}>
              <SpeciesView />
            </SpeciesProvider>
          </AppProvider>
        </BrowserRouter>,
      );
      await act(() => api.getSpecies());
    });

    afterEach(cleanup);

    describe('it shows main page elements', () => {
      it('then shows "Add New Species" button', () => {
        expect(screen.getByText(/Add New Species/i)).toBeTruthy();
      });

      it('then shows "Combine Species" button', () => {
        expect(screen.getByText(/Combine Species/i)).toBeTruthy();
      });

      it('species list should be 2', () => {
        expect(speciesValues.speciesList).toHaveLength(3);
      });

      // shows a table with headers
      // shows navigation menu
    });

    describe('when the "Add New Species" button is clicked', () => {
      beforeEach(() => {
        userEvent.click(screen.getByText(/Add New Species/i));
      });

      it('see popup with species detail form', () => {
        expect(screen.getByText(/Species Detail/i)).toBeTruthy();
      });

      it('has inputs for name and description', () => {
        const dialog = screen.getByRole(/dialog/i);
        const item = within(dialog).getByLabelText(/name/i);
        expect(item).toBeTruthy();
      });

      it('has buttons to save and cancel', () => {
        const dialog = screen.getByRole(/dialog/i);
        expect(within(dialog).getByText(/save/i)).toBeTruthy();
      });
    });

    // [TODO]: MORE TESTS
    // when the combine species button is clicked
    //it fails if two species aren't selected
    //opens if 2+ species are selected
    //shows those species names in the popup
    //has inputs for name and description
    //has buttons to save and cancel

    describe('when creating a new species', () => {
      beforeEach(async () => {
        // await api.createSpecies({ name: 'water melon' });
        userEvent.click(screen.getByText(/Add New Species/i));
        const dialog = screen.getByRole(/dialog/i);
        const inputName = screen.getByLabelText(/name/i);
        const inputDesc = screen.getByLabelText(/description/i);
        const saveBtn = screen.getByText(/Save/i);

        userEvent.type(inputName, 'water melon');
        expect(inputName.value).toBe('water melon');

        userEvent.type(inputDesc, 'test');
        expect(inputDesc.value).toBe('test');

        expect(screen.getByDisplayValue('water melon')).toBeTruthy();
        expect(screen.getByDisplayValue('test')).toBeTruthy();

        userEvent.click(saveBtn);

        // mock-adding new species --- DOESN'T UPDATE state
        // speciesValues.speciesList.push({
        //   id: 2,
        //   name: 'water melon',
        //   desc: 'fruit',
        // });

        // wait for it... to complete & dialog to close
        waitForElementToBeRemoved(dialog);
        //---- the last 2 tests work w/o this line but get act() errors in the console.
        //---- the errors go away w/this line but then tests fail
      });

      afterEach(cleanup);

      it('api.createSpecies should be called with "water melon"', () => {
        expect(api.createSpecies.mock.calls[0][0].name).toBe('water melon');
      });

      // it('species list should be 3 (1 added)', () => {
      //   expect(speciesValues.speciesList).toHaveLength(3);
      // });

      // it('has 3 species', () => {
      //   const items = screen.getAllByTestId('species');
      //   // screen.logTestingPlaygroundURL();
      //   const speciesNames = items.map((el) => el.textContent);
      //   // console.log('speciesNames', speciesNames);
      //   expect(items).toHaveLength(3);
      // });

      // it('added species should show on the screen', () => {
      //   expect(screen.getByText('water melon')).toBeTruthy();
      // });
    });
  });
});
Example #21
Source File: verify.test.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('Verify', () => {
  let growerApi;
  let captureApi;
  //mock the growers api
  growerApi = require('../../api/growers').default;

  growerApi.getCount = () => {
    log.debug('mock getCount:');
    return Promise.resolve({ count: 2 });
  };
  growerApi.getGrower = () => {
    log.debug('mock getGrower:');
    return Promise.resolve(GROWER);
  };
  growerApi.getGrowerRegistrations = () => {
    log.debug('mock getGrowerRegistrations:');
    return Promise.resolve([]);
  };
  growerApi.getGrowerSelfies = (id) => {
    log.debug('mock getGrowerSelfies:');
    return Promise.resolve([{ planterPhotoUrl: '' }, { planterPhotoUrl: '' }]);
  };

  // mock the treeTrackerApi
  captureApi = require('../../api/treeTrackerApi').default;

  captureApi.getCaptureImages = () => {
    log.debug('mock getCaptureImages:');
    return Promise.resolve(CAPTURES);
  };
  captureApi.getCaptureCount = () => {
    log.debug('mock getCaptureCount:');
    return Promise.resolve({ count: 4 });
  };
  captureApi.getCaptureById = (_id) => {
    log.debug('mock getCaptureById:');
    return Promise.resolve(CAPTURE);
  };
  captureApi.getSpecies = () => {
    log.debug('mock getSpecies:');
    return Promise.resolve(SPECIES);
  };
  captureApi.getSpeciesById = (_id) => {
    log.debug('mock getSpeciesById:');
    return Promise.resolve(SPECIES[0]);
  };
  captureApi.getCaptureCountPerSpecies = () => {
    log.debug('mock getCaptureCountPerSpecies:');
    return Promise.resolve({ count: 7 });
  };
  captureApi.getTags = () => {
    log.debug('mock getTags:');
    return Promise.resolve(TAGS);
  };
  captureApi.getTagById = (_id) => {
    log.debug('mock getTagById:');
    return Promise.resolve(TAG);
  };
  captureApi.getOrganizations = () => {
    log.debug('mock getOrganizations:');
    return Promise.resolve(ORGS);
  };

  describe('with default values', () => {
    beforeEach(async () => {
      render(
        <ThemeProvider theme={theme}>
          <BrowserRouter>
            <AppProvider value={{ orgList: ORGS }}>
              <GrowerContext.Provider value={growerValues}>
                <VerifyProvider value={verifyValues}>
                  <SpeciesProvider value={speciesValues}>
                    <TagsContext.Provider value={tagsValues}>
                      <Verify />
                    </TagsContext.Provider>
                  </SpeciesProvider>
                </VerifyProvider>
              </GrowerContext.Provider>
            </AppProvider>
          </BrowserRouter>
        </ThemeProvider>
      );

      await act(() => captureApi.getCaptureImages());
      await act(() => captureApi.getCaptureCount());
      // await act(() => captureApi.getTags());
    });

    afterEach(cleanup);

    it('renders filter top', () => {
      const filter = screen.getByRole('button', { name: /filter/i });
      userEvent.click(filter);
      // screen.logTestingPlaygroundURL();

      const verifyStatus = screen.getByLabelText(/awaiting verification/i);
      expect(verifyStatus).toBeInTheDocument();

      const tokenStatus = screen.getByLabelText(/token status/i);
      expect(tokenStatus).toBeInTheDocument();
    });

    it('renders number of applied filters', async () => {
      const filter = screen.getByRole('button', { name: /filter 1/i });
      userEvent.click(filter);
      expect(screen.getByText(/awaiting verification/i)).toBeInTheDocument();
      //data won't actually be filtered but filters should be selected
      //why was this set to expect 2 filters?
      expect(verifyValues.filter.countAppliedFilters()).toBe(1);

      let dropdown = screen.getByTestId('org-dropdown');
      expect(dropdown).toBeInTheDocument();
      let button = within(dropdown).getByRole('button', {
        name: /all/i,
      });
      userEvent.click(button);
      // the actual list of orgs is displayed in a popup that is not part of FilterTop
      // this list is the default list
      const orglist = screen.getByRole('listbox');

      const orgSelected = screen.getByRole('option', { name: /not set/i });

      userEvent.selectOptions(orglist, orgSelected);

      userEvent.click(screen.getByText(/apply/i));
      expect(screen.getByRole('button', { name: /filter 1/i })).toBeTruthy();
      //this function is still returning 1
      expect(verifyValues.filter.countAppliedFilters()).toBe(1);
    });

    // it('renders side panel', () => {
    //   // screen.logTestingPlaygroundURL();
    //   // expect(screen.getByText(/planters per page: 24/i));
    // });

    it('renders captures gallery', () => {
      const pageSize = screen.getAllByText(/captures per page:/i);
      expect(pageSize).toHaveLength(2);

      expect(screen.getByText(/4 captures/i));
    });

    it('renders capture details', () => {
      const captureDetails = screen.getAllByRole('button', {
        name: /capture details/i,
      });
      expect(captureDetails).toHaveLength(4);
      userEvent.click(captureDetails[0]);
      expect(screen.getByText(/capture data/i)).toBeInTheDocument();
      expect(screen.getByText(/grower identifier/i)).toBeInTheDocument();
      expect(screen.getByText(/[email protected]/i)).toBeInTheDocument();
      expect(screen.getByText(/device identifier/i)).toBeInTheDocument();
      // expect(screen.getByText(/1 - abcdef123456/i)).toBeInTheDocument();
      expect(screen.getByText(/verification status/i)).toBeInTheDocument();
      expect(screen.getByText(/token status/i)).toBeInTheDocument();
    });

    it('renders grower details', () => {
      const growerDetails = screen.getAllByRole('button', {
        name: /grower details/i,
      });
      expect(growerDetails).toHaveLength(4);
      userEvent.click(growerDetails[0]);
      // screen.logTestingPlaygroundURL();

      expect(screen.getByText(/country/i)).toBeInTheDocument();
      expect(screen.getByText(/organization/i)).toBeInTheDocument();
      expect(screen.getByText(/person ID/i)).toBeInTheDocument();
      expect(screen.getByText(/ID:/i)).toBeInTheDocument();
      expect(screen.getByText(/email address/i)).toBeInTheDocument();
      expect(screen.getByText(/phone number/i)).toBeInTheDocument();
      expect(screen.getByText(/registered/i)).toBeInTheDocument();
    });

    // it('renders edit planter', () => {
    //   const planterDetails = screen.getAllByRole('button', {
    //     name: /planter details/i,
    //   });
    //   userEvent.click(planterDetails[0]);

    //   screen.logTestingPlaygroundURL();
    //   //
    //   const editPlanter = screen.getByTestId(/edit-planter/i);
    //   expect(editPlanter).toBeInTheDocument();
    //   userEvent.click(editPlanter);
    // });
  });
});
Example #22
Source File: App.test.js    From Simplify-Testing-with-React-Testing-Library with MIT License 4 votes vote down vote up
describe('Integration: Budget App', () => {
  function setOneDollarIncome() {
    user.click(screen.getByText(/set income/i));
    user.type(screen.getByRole('spinbutton'), '1');
    user.click(screen.getByText(/submit/i));
  }

  function createCarBudget(amount = '5') {
    user.click(screen.getByText(/create new budget/i));
    user.selectOptions(screen.getByRole('combobox', { name: /category/i }), [
      screen.getByText('Auto'),
    ]);
    user.type(screen.getByRole('spinbutton'), amount);
    user.click(screen.getByText(/add budget/i));
  }

  test('SetIncome, given income amount, sets income', () => {
    render(<App />);

    setOneDollarIncome();
    const leftOverBudget = screen.getByText(/left over:/i);
    const leftOverBudgetAmount = within(leftOverBudget).getByText(/\$1/i);

    expect(leftOverBudgetAmount).toBeInTheDocument();
    expect(
      screen.getByRole('heading', { name: /income: \$1/i })
    ).toBeInTheDocument();
  });

  describe('CreateNewBudget', () => {
    test.each`
      budgetAmount | spending           | leftOver
      ${'4'}       | ${'Spending: $5'}  | ${'$-4'}
      ${'5'}       | ${'Spending: $5'}  | ${'$-4'}
      ${'6'}       | ${'Spending: $10'} | ${'$-9'}
    `(
      'given budget, updates budget summary',
      ({ budgetAmount, spending, leftOver }) => {
        render(<App />);
        setOneDollarIncome();

        createCarBudget(budgetAmount);
        const leftOverBudget = screen.getByText(/left over:/i);
        const leftOverBudgetAmount = within(leftOverBudget).getByText(leftOver);

        expect(leftOverBudgetAmount).toBeInTheDocument();
        expect(
          screen.getByRole('heading', { name: spending })
        ).toBeInTheDocument();
      }
    );
    test('given budget, displays budget chart', () => {
      render(<App />);
      setOneDollarIncome();
      createCarBudget();

      expect(screen.getByTestId('chart')).toBeInTheDocument();
    });
  });
  describe('Budget', () => {
    test('given budget, displays details', () => {
      render(<App />);
      setOneDollarIncome();
      createCarBudget();

      const budgetList = screen.getByRole('listitem');

      expect(within(budgetList).getByText(/auto/i)).toBeInTheDocument();
      expect(
        screen.getByRole('heading', { name: /\$0 of \$5/i })
      ).toBeInTheDocument();
    });

    test('given budget expense, updates budget progress', () => {
      render(<App />);
      setOneDollarIncome();
      createCarBudget();

      user.click(screen.getByRole('button', { name: /arrowright/i }));

      expect(
        screen.getByRole('heading', { name: /\$5 of \$5/i })
      ).toBeInTheDocument();
    });
  });

  test('DeleteBudget, given deleted budget, budget removed from DOM', () => {
    render(<App />);
    setOneDollarIncome();
    createCarBudget();

    user.click(screen.getByLabelText(/trash can/i));

    expect(screen.queryByRole('listitem')).not.toBeInTheDocument();
  });
});
Example #23
Source File: PeoplePage.test.jsx    From sgmr-service with MIT License 4 votes vote down vote up
describe('People page', () => {
  const mockAxios = new MockAdapter(axios);
  beforeEach(() => {
    mockAxios.reset();
    NotificationBanner.mockReturnValue(null);
  });

  it('should show the list of people saved on your account', async () => {
    mockAxios
      .onGet(`${PEOPLE_URL}`, 'people')
      .reply(200, MockedAccountPeopleList);
    renderPage();

    await waitFor(() => {
      expect(screen.getByText('Saved people')).toBeInTheDocument();
      expect(screen.getByText('Fred Flintstone')).toBeInTheDocument();
      expect(screen.getByText('1Fred')).toBeInTheDocument();
      expect(screen.getByText('01/01/2025')).toBeInTheDocument();
      expect(screen.getByText('Barney Rubble')).toBeInTheDocument();
      expect(screen.getByText('2Barney')).toBeInTheDocument();
      expect(screen.getByText('01/12/2030')).toBeInTheDocument();
      expect(screen.getByText('Add new person')).toHaveClass('govuk-button govuk-button--secondary');
    });
  });

  it('should show the the h1 & add person button if there are 0 people saved on your account', async () => {
    mockAxios
      .onGet(`${PEOPLE_URL}`, 'people')
      .reply(204);
    renderPage();

    await waitFor(() => {
      expect(screen.getByText('Saved people')).toBeInTheDocument();
      expect(screen.getByText('Add new person')).toHaveClass('govuk-button govuk-button--secondary');
    });
  });

  it('should sort the list of people alphabetically by last name, firstname', async () => {
    mockAxios
      .onGet(`${PEOPLE_URL}`, 'people')
      .reply(200, MockedAccountPeopleUnsortedList);
    renderPage();

    await waitFor(() => {
      const rows = screen.getAllByTestId('row');
      // test first names appear in correct order based on sort by lastName>firstName
      expect(within(rows[0]).queryByText('Fred Flintstone')).toBeInTheDocument();
      expect(within(rows[1]).queryByText('Pebbles Flintstone')).toBeInTheDocument();
      expect(within(rows[2]).queryByText('Wilma Flintstone')).toBeInTheDocument();
      expect(within(rows[3]).queryByText('BamBam Rubble')).toBeInTheDocument();
      expect(within(rows[4]).queryByText('Barney Rubble')).toBeInTheDocument();
      expect(within(rows[5]).queryByText('Betty Rubble')).toBeInTheDocument();
    });
  });

  it('should take you to the add person form when you click add new person', async () => {
    mockAxios
      .onGet(`${PEOPLE_URL}`, 'people')
      .reply(200, MockedAccountPeopleList);
    renderPage();

    await waitFor(() => {
      expect(screen.getByText('Add new person')).toHaveClass('govuk-button govuk-button--secondary');
      fireEvent.click(screen.getByText('Add new person'));
    });

    await waitFor(() => {
      expect(mockHistoryPush).toHaveBeenCalledWith('/people/save-person/page-1');
    });
  });

  it('should take you to the DELETE person page when you click remove', async () => {
    mockAxios
      .onGet(`${PEOPLE_URL}`, 'people')
      .reply(200, MockedAccountPeopleList);
    renderPage();

    await waitFor(() => {
      expect(screen.getByText('Fred Flintstone')).toBeInTheDocument();
      expect(screen.getAllByText('Remove')).toHaveLength(3);
      fireEvent.click(screen.getAllByText('Remove')[0]);
    });

    await waitFor(() => {
      expect(mockHistoryPush).toHaveBeenCalledWith('/people/1/delete');
    });
  });

  it('should take you to the edit person form when you click update', async () => {
    mockAxios
      .onGet(`${PEOPLE_URL}`, 'people')
      .reply(200, MockedAccountPeopleList);
    renderPage();

    await waitFor(() => {
      expect(screen.getByText('Fred Flintstone')).toBeInTheDocument();
      expect(screen.getAllByText('Update')).toHaveLength(3);
      fireEvent.click(screen.getAllByText('Update')[2]);
    });

    await waitFor(() => {
      expect(mockHistoryPush).toHaveBeenCalledWith('/people/edit-person/page-1', { peopleId: '3', source: 'edit' });
    });
  });
});
Example #24
Source File: app.spec.js    From astroport-lbp-frontend with MIT License 4 votes vote down vote up
describe('App', () => {
  it('renders Scheduled and Previous Token Sales cards', async () => {
    const dateNowSpy = jest
      .spyOn(Date, 'now')
      .mockImplementation(() => new Date(2021, 5, 9).getTime());

    // Mock toLocaleString to always use en-US locale in EDT timezone
    const toLocaleStringSpy = jest.spyOn(Date.prototype, 'toLocaleString');
    toLocaleStringSpy.mockImplementation(
      function (locale, options) {
        return new Intl.DateTimeFormat('en-US', { ...options, timeZone: 'America/New_York' }).format(this);
      }
    )

    const currentPair = buildPair({
      startTime: Math.floor(Date.UTC(2021, 5, 8, 12)/1000),
      endTime: Math.floor(Date.UTC(2021, 5, 10, 12)/1000),
      tokenContractAddr: 'terra3',
      contractAddr: 'terra3-pair-addr'
    });

    // This pair would be displayed as scheduled if permitted
    const unpermittedPair = buildPair({
      startTime: Math.floor(Date.UTC(2021, 5, 10, 12)/1000),
      endTime: Math.floor(Date.UTC(2021, 5, 14, 12)/1000),
      tokenContractAddr: 'terra4',
      contractAddr: 'terra4-pair-addr'
    });

    getLBPs.mockResolvedValue([
      buildPair({
        startTime: Math.floor(Date.UTC(2021, 0, 1, 12)/1000),
        endTime: Math.floor(Date.UTC(2021, 0, 4, 12)/1000),
        tokenContractAddr: 'terra1',
        contractAddr: 'terra1-pair-addr'
      }),
      buildPair({
        startTime: Math.floor(Date.UTC(2021, 5, 10, 12)/1000),
        endTime: Math.floor(Date.UTC(2021, 5, 14, 12)/1000),
        tokenContractAddr: 'terra2',
        contractAddr: 'terra2-pair-addr'
      }),
      unpermittedPair,
      currentPair
    ]);

    getPairInfo.mockResolvedValue(currentPair);

    getTokenInfo.mockImplementation((_, address) => (
      {
        terra1: {
          name: 'Foo'
        },
        terra2: {
          name: 'Bar'
        },
        terra3: {
          name: 'Baz'
        },
        terra4: {
          name: 'Bad'
        }
      }[address]
    ));

    render(<App />);

    // Heading with sale token name
    expect(await screen.findByText('Baz Token Sale')).toBeInTheDocument();

    // Current token info component
    expect(await screen.findByText('Current Token Info')).toBeInTheDocument();

    // Tokens are in the correct cards with the correct time/dates
    const scheduledCard = (await screen.findByText('Scheduled Token Sales')).closest('div')
    const previousCard = (await screen.findByText('Previous Token Sales')).closest('div')

    const barCell = await within(scheduledCard).findByText('Bar');
    expect(barCell).toBeInTheDocument();
    expect(within(barCell.closest('tr')).queryByText('06/10/2021, 08:00 AM EDT')).toBeInTheDocument();

    const fooCell = await within(previousCard).findByText('Foo')
    expect(fooCell).toBeInTheDocument();
    expect(within(fooCell.closest('tr')).queryByText('01/01/2021 - 01/04/2021')).toBeInTheDocument();

    // Tokens are not present in the wrong cards
    expect(within(scheduledCard).queryByText('Foo')).toBeNull();
    expect(within(scheduledCard).queryByText('Baz')).toBeNull();
    expect(within(previousCard).queryByText('Bar')).toBeNull();
    expect(within(previousCard).queryByText('Baz')).toBeNull();

    // It should have fetched info for the current sale
    expect(getPairInfo).toHaveBeenCalledTimes(1);
    expect(getPairInfo).toHaveBeenCalledWith(expect.anything(), 'terra3-pair-addr');

    // Unpermitted pair should never be displayed
    expect(screen.queryByText('Bad')).not.toBeInTheDocument();

    dateNowSpy.mockRestore();
  });

  it('displays partial wallet address after successful browser extension connection', async () => {
    connectExtension.mockResolvedValue({ address: 'terra1234567890' });

    const currentPair = buildPair({ contractAddr: 'terra1-pair-addr' });

    getLBPs.mockResolvedValue([
      currentPair
    ]);

    getPairInfo.mockResolvedValue(currentPair);

    getTokenInfo.mockResolvedValue({
      name: 'Foo'
    });

    render(<App />);

    // Wait for data to load and Connect Wallet button to become visible
    await screen.findByText('Connect Wallet');

    // Wallet address should not yet be displayed
    expect(screen.queryByText('567890')).toBeNull();

    await act(async () => {
      await userEvent.click(screen.getByText('Connect Wallet'));
    })

    expect(screen.getByText('terra1...567890')).toBeInTheDocument();
  });

  it('automatically reconnects extension if it was connected previously', async () => {
    const getItemSpy = jest.spyOn(window.localStorage.__proto__, 'getItem');
    getItemSpy.mockImplementation((key) => {
      return {
        terraStationExtensionPreviouslyConnected: true
      }[key]
    });

    connectExtension.mockResolvedValue({ address: 'terra1234567890' });

    const currentPair = buildPair({ contractAddr: 'terra1-pair-addr' });

    getLBPs.mockResolvedValue([
      currentPair
    ]);

    getPairInfo.mockResolvedValue(currentPair);

    getTokenInfo.mockResolvedValue({
      name: 'Foo'
    });

    render(<App />);

    expect(await screen.findByText('terra1...567890')).toBeInTheDocument();

    expect(getItemSpy).toHaveBeenCalledTimes(1);
    expect(getItemSpy).toHaveBeenCalledWith('terraStationExtensionPreviouslyConnected');
  });

  it('disconnects wallet', async () => {
    const getItemSpy = jest.spyOn(window.localStorage.__proto__, 'getItem');
    const removeItemSpy = jest.spyOn(window.localStorage.__proto__, 'removeItem');
    getItemSpy.mockImplementation((key) => {
      return {
        terraStationExtensionPreviouslyConnected: true
      }[key]
    });

    connectExtension.mockResolvedValue({ address: 'terra1234567890' });

    const currentPair = buildPair({ contractAddr: 'terra1-pair-addr'} );

    getLBPs.mockResolvedValue([
      currentPair
    ]);

    getPairInfo.mockResolvedValue(currentPair);

    getTokenInfo.mockResolvedValue({
      name: 'Foo'
    });

    render(<App />);

    expect(await screen.findByText('terra1...567890')).toBeInTheDocument();

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Disconnect wallet' }));
    })

    expect(screen.queryByText('terra1...567890')).not.toBeInTheDocument();

    expect(getItemSpy).toHaveBeenCalledTimes(1);
    expect(getItemSpy).toHaveBeenCalledWith('terraStationExtensionPreviouslyConnected');

    expect(removeItemSpy).toHaveBeenCalledTimes(1);
    expect(removeItemSpy).toHaveBeenCalledWith('terraStationExtensionPreviouslyConnected');
  });
});
Example #25
Source File: swap_card.spec.js    From astroport-lbp-frontend with MIT License 4 votes vote down vote up
describe('SwapCard', () => {
  const pair = buildPair({
    contractAddr: 'terra1',
    tokenContractAddr: 'terra2'
  });

  const saleTokenInfo = {
    symbol: 'FOO',
    decimals: 5
  };

  const ustExchangeRate = 0.99;

  let onSwapTxMined;

  beforeEach(() => {
    onSwapTxMined = jest.fn();
  });

  function renderCard({ ustPrice } = {}) {
    render(
      <SwapCard
        pair={pair}
        saleTokenInfo={saleTokenInfo}
        ustExchangeRate={ustExchangeRate}
        ustPrice={ustPrice || new Dec(1)}
        onSwapTxMined={onSwapTxMined}
      />
    );
  }

  it('runs simulation, populates "to" field with simulated amount received, and calculates price impact', async () => {
    getSimulation.mockResolvedValue({
      return_amount: '200000000' // 0.50 UST valuation
    });

    getBalance.mockResolvedValue(2000 * 1e6); // Simulation does a basic balance check

    renderCard({ ustPrice: new Dec(0.49) });

    // Wait for balance
    await waitForBalances({ fromBalance: '2,000' });

    const fromInput = screen.getByLabelText('From');
    const toInput = screen.getByLabelText('To (estimated)');

    await act(async () => {
      // We need to delay between inputs otherwise we end up with a field value of "1"
      await userEvent.type(fromInput, '1000', { delay: 1 });
    });

    // "From" value is correctly converted to USD
    const fromField = fromInput.closest('.border');
    expect(within(fromField).getByText('($990.00)')).toBeInTheDocument(); // 1000 * 0.99

    // "To" value is properly set to value returned by simulation
    expect(toInput).toHaveDisplayValue('2000');

    // "To" value is correctly converted to USD
    const toField = toInput.closest('.border');
    expect(within(toField).getByText('($970.20)')).toBeInTheDocument(); // 2000 * 0.49 * .99

    // Simulated price is $0.01 higher than the spot price ($0.49),
    // so the price impact is $0.01/$0.49 = 0.0204
    expect(getDescriptionByTermEl(screen.getByText('Price Impact'))).toHaveTextContent('2.04%');

    expect(getSimulation).toHaveBeenCalledWith(
      mockTerraClient,
      'terra1',
      new Int(1000000000),
      {
        native_token: {
          denom: 'uusd'
        }
      }
    );
  });

  it('runs reverse simulation and populates "from" field with simulated amount required', async () => {
    getReverseSimulation.mockResolvedValue({
      offer_amount: '42000000'
    });

    // Simulation does a basic balance check
    getBalance.mockResolvedValue(2000 * 1e6);
    getTokenBalance.mockResolvedValue(2000 * 1e6);

    renderCard({ ustPrice: new Dec(5.95) });

    const toInput = screen.getByLabelText('To (estimated)');

    // Wait for balances
    await waitForBalances({ fromBalance: '2,000' });

    await act(async () => {
      await userEvent.type(toInput, '7');
    });

    // "From" value is properly set to value returned by reverse simulation
    expect(screen.getByLabelText('From')).toHaveDisplayValue('42');

    // Simulated price is $0.05 higher than the spot price ($5.95),
    // so the price impact is $0.05/$5.95 = 0.0084
    expect(getDescriptionByTermEl(screen.getByText('Price Impact'))).toHaveTextContent('0.84%');

    expect(getReverseSimulation).toHaveBeenCalledWith(
      mockTerraClient,
      'terra1',
      new Int(700000),
      {
        token: {
          contract_addr: 'terra2'
        }
      }
    );
  });

  it('runs new simulation when assets are reversed', async () => {
    getSimulation.mockImplementation((_, pairAddress, amount, offerAssetInfo) => {
      if(offerAssetInfo.native_token) {
        // Mocked response when offer asset is the native token
        return {
          return_amount: '210000000' // 5 decimals
        };
      } else {
        // Mocked response when offer asset is the sale token
        return {
          return_amount: '2000000' // 6 decimals
        }
      }
    });

    getBalance.mockResolvedValue(2000 * 1e6);
    getTokenBalance.mockResolvedValue(2000 * 1e6);

    renderCard({ ustPrice: new Dec(.48) });

    // Wait for balances
    await waitForBalances({ fromBalance: '2,000' });

    // First enter a from value (UST -> FOO)
    const fromInput = screen.getByLabelText('From');
    await act(async () => {
      await userEvent.type(fromInput, '4');
    });

    // Assert simulated value set
    expect(screen.getByLabelText('To (estimated)')).toHaveDisplayValue('2100');

    // Reverse the assets (FOO -> UST)
    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Reverse assets' }));
    });

    // "To" value is properly set to value returned by simulation
    expect(screen.getByLabelText('To (estimated)')).toHaveDisplayValue('2');

    // Simulated price is $0.02 higher than the spot price ($0.48),
    // so the price impact is $0.02/$0.48 = 0.0417
    expect(getDescriptionByTermEl(screen.getByText('Price Impact'))).toHaveTextContent('4.17%');

    // First simulation when initial "from" amount was entered
    expect(getSimulation).toHaveBeenCalledWith(
      mockTerraClient,
      'terra1',
      new Int(4 * 1e6), // 6 decimals
      {
        native_token: {
          denom: 'uusd'
        }
      }
    );

    // Second simulation when "from" asset was changed
    expect(getSimulation).toHaveBeenCalledWith(
      mockTerraClient,
      'terra1',
      new Int(4 * 1e5), // 5 decimals
      {
        token: {
          contract_addr: 'terra2'
        }
      }
    );
  });

  it('performs native -> token swap, displays success message, and updates balances', async () => {
    // Simulation is performed on input change
    getSimulation.mockResolvedValue({
      return_amount: String(5 * 1e5)
    });

    // Before balances
    getBalance.mockResolvedValueOnce(2000000);
    getTokenBalance.mockResolvedValueOnce(0);

    // After balances
    getBalance.mockResolvedValueOnce(1000000);
    getTokenBalance.mockResolvedValueOnce(5 * 1e5);

    // Mock fee fetching
    const fee = jest.fn();
    estimateFee.mockResolvedValue(fee);

    // Successful post
    postMsg.mockResolvedValue({ txhash: '123ABC' });

    // Stub out balance check
    sufficientBalance.mockResolvedValue(true);

    renderCard();

    // Initial balances
    await waitForBalances({ fromBalance: '2', toBalance: '0' });

    const fromInput = screen.getByLabelText('From');
    await act(async () => {
      await userEvent.type(fromInput, '1');
    });

    // Mock mined tx to trigger balance update
    mockTerraClient.tx.txInfo.mockResolvedValue({});

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Swap' }));
    });

    expect(screen.getByText('Transaction Complete')).toBeInTheDocument();

    const txLink = screen.getByRole('link', { name: '123ABC' });
    expect(txLink).toBeInTheDocument();
    expect(txLink.getAttribute('href')).toEqual('https://finder.terra.money/testnet/tx/123ABC');

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Continue' }));
    });

    // New balances
    await waitForBalances({ fromBalance: '1', toBalance: '5' });

    // Estimates fee and posts message with estimated fee
    const msg = buildSwapFromNativeTokenMsg({
      walletAddress: 'terra42',
      pair,
      intAmount: new Int(1e6)
    });
    expect(estimateFee).toHaveBeenCalledTimes(1);
    expect(estimateFee).toHaveBeenCalledWith(mockTerraClient, msg);

    expect(postMsg).toHaveBeenCalledTimes(1);
    expect(postMsg).toHaveBeenCalledWith(mockTerraClient, { msg, fee });

    // Fetches tx info
    expect(mockTerraClient.tx.txInfo).toHaveBeenCalledWith('123ABC');

    // Invokes callback
    expect(onSwapTxMined).toHaveBeenCalledTimes(1);
  });

  it('performs token -> native token swap, displays success message, and updates balances', async () => {
    // Simulation is performed on input change
    getSimulation.mockResolvedValue({
      return_amount: String(1e6)
    });

    // Before balances
    getTokenBalance.mockResolvedValueOnce(10 * 1e5);
    getBalance.mockResolvedValueOnce(0);

    // After balances
    getTokenBalance.mockResolvedValueOnce(5 * 1e5);
    getBalance.mockResolvedValueOnce(1e6);

    // Mock fee fetching
    const fee = jest.fn();
    estimateFee.mockResolvedValue(fee);

    // Successful post
    postMsg.mockResolvedValue({ txhash: 'ABC123' });

    // Stub out balance check
    sufficientBalance.mockResolvedValue(true);

    renderCard();

    // Initial balances
    await waitForBalances({ fromBalance: '0', toBalance: '10' });

    // Reverse the assets (FOO -> UST)
    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Reverse assets' }));
    });

    const fromInput = screen.getByLabelText('From');
    await act(async () => {
      await userEvent.type(fromInput, '5');
    });

    // Mock mined tx to trigger balance update
    mockTerraClient.tx.txInfo.mockResolvedValue({});

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Swap' }));
    });

    expect(screen.getByText('Transaction Complete')).toBeInTheDocument();

    const txLink = screen.getByRole('link', { name: 'ABC123' });
    expect(txLink).toBeInTheDocument();
    expect(txLink.getAttribute('href')).toEqual('https://finder.terra.money/testnet/tx/ABC123');

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Continue' }));
    });

    // New balances
    await waitForBalances({ fromBalance: '5', toBalance: '1' });

    // Estimates fee and posts message with estimated fee
    const msg = buildSwapFromContractTokenMsg({
      walletAddress: 'terra42',
      pair,
      intAmount: new Int(5e5)
    });
    expect(estimateFee).toHaveBeenCalledTimes(1);
    expect(estimateFee).toHaveBeenCalledWith(mockTerraClient, msg);

    expect(postMsg).toHaveBeenCalledTimes(1);
    expect(postMsg).toHaveBeenCalledWith(mockTerraClient, { msg, fee });

    // Fetches tx info
    expect(mockTerraClient.tx.txInfo).toHaveBeenCalledWith('ABC123');
  });

  it('performs swap after setting from amount to balance less fees when swapping from native token', async () => {
    getBalance.mockResolvedValue(new Int(1000 * 1e6));
    getTokenBalance.mockResolvedValue(new Int(0));

    const fee = new StdFee(200000, new Coins(
      [new Coin('uusd', 999999)]
    ));
    feeForMaxNativeToken.mockResolvedValue(fee);

    // Setting max from asset triggers a forward simulation
    getSimulation.mockResolvedValue({ return_amount: '500000000' });

    // Successful post
    postMsg.mockResolvedValue({ txhash: '123ABC' });

    // Stub out balance check
    sufficientBalance.mockResolvedValue(true);

    renderCard();

    // Wait for balances to load
    await waitForBalances({ fromBalance: '1,000' });

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Max' }));
    });

    // "From" value is properly set to value balance less fees
    expect(screen.getByLabelText('From')).toHaveDisplayValue('999.000001');

    // Perform swap
    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Swap' }));
    });

    expect(screen.getByText('Transaction Complete')).toBeInTheDocument();

    // Posts message with max fee
    const msg = buildSwapFromNativeTokenMsg({
      walletAddress: 'terra42',
      pair,
      intAmount: new Int(999000001)
    });
    expect(postMsg).toHaveBeenCalledTimes(1);
    expect(postMsg).toHaveBeenCalledWith(mockTerraClient, { msg, fee });

    // Does not estimate fee for from amount
    // (this is calculated differently for "max" amount)
    expect(estimateFee).not.toHaveBeenCalled();
  });

  it('performs swap after setting from amount to balance of contract token', async () => {
    getBalance.mockResolvedValue(new Int(1000 * 1e6));
    getTokenBalance.mockResolvedValue(new Int(5000 * 1e5));

    const fee = new StdFee(200000, new Coins(
      [new Coin('uusd', 30000)]
    ));
    estimateFee.mockResolvedValue(fee);

    // Setting max from asset triggers a forward simulation
    getSimulation.mockResolvedValue({ return_amount: '1000000000' });

    // Successful post
    postMsg.mockResolvedValue({ txhash: '123ABC' });

    // Stub out balance check
    sufficientBalance.mockResolvedValue(true);

    renderCard();

    // Wait for balances to load
    await waitForBalances({ fromBalance: '1,000', toBalance: '5,000' });

    // Reverse the assets (FOO -> UST)
    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Reverse assets' }));
    });

    // Use max FOO tokens
    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Max' }));
    });

    // "From" value is properly set to entire token balance
    expect(screen.getByLabelText('From')).toHaveDisplayValue('5000');

    // Perform swap
    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Swap' }));
    });

    expect(screen.getByText('Transaction Complete')).toBeInTheDocument();

    // Posts message with max contract tokens
    // and still estimates fee (uusd)
    const msg = buildSwapFromContractTokenMsg({
      walletAddress: 'terra42',
      pair,
      intAmount: new Int(5000 * 1e5)
    });
    expect(estimateFee).toHaveBeenCalledTimes(1);
    expect(estimateFee).toHaveBeenCalledWith(mockTerraClient, msg);

    expect(postMsg).toHaveBeenCalledTimes(1);
    expect(postMsg).toHaveBeenCalledWith(mockTerraClient, { msg, fee });
  });

  it('conveys error state to user and does not invoke onSwapTxMined callback if extension responds with error when sending message', async() => {
    // Simulation is performed on input change
    getSimulation.mockResolvedValue({
      return_amount: String(1e6)
    });

    getBalance.mockResolvedValue(10 * 1e6);
    getTokenBalance.mockResolvedValue(0);
    sufficientBalance.mockResolvedValue(true);

    // Failed post
    postMsg.mockRejectedValue({ code: 1 });

    renderCard();

    // Wait for balances
    await waitForBalances({ fromBalance: '10' });

    await act(async () => {
      await userEvent.type(screen.getByLabelText('From'), '5');
    });

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Swap' }));
    });

    expect(screen.queryByText('Error submitting transaction')).toBeInTheDocument();

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Continue' }));
    });

    expect(screen.queryByText('Error submitting transaction')).not.toBeInTheDocument();

    // Does not invoke callback
    expect(onSwapTxMined).not.toHaveBeenCalled();
  });

  it('displays and reports error when an error is thrown while selecting max balance', async() => {
    getBalance.mockResolvedValue(new Int(1000 * 1e6));
    getTokenBalance.mockResolvedValue(new Int(0));

    const mockError = jest.fn();
    feeForMaxNativeToken.mockRejectedValue(mockError);

    renderCard();

    // Wait for balances to load
    await waitForBalances({ fromBalance: '1,000' });

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Max' }));
    });

    expect(screen.queryByText('Unable to swap max balance')).toBeInTheDocument();
    expect(reportException).toHaveBeenCalledTimes(1);
    expect(reportException).toHaveBeenCalledWith(mockError);
  });

  it('displays and reports error when simulation fails', async () => {
    const mockError = jest.fn();
    getSimulation.mockRejectedValue(mockError);

    getBalance.mockResolvedValue(2000 * 1e6); // Simulation does a basic balance check

    renderCard({ ustPrice: new Dec(0.49) });

    // Wait for balance
    await waitForBalances({ fromBalance: '2,000' });

    const fromInput = screen.getByLabelText('From');
    const toInput = screen.getByLabelText('To (estimated)');

    await act(async () => {
      await userEvent.type(fromInput, '1');
    });

    expect(screen.queryByText('Simulation failed')).toBeInTheDocument();

    // "To" value is not set
    expect(toInput).toHaveDisplayValue('');

    // "To" value is still $0
    const toField = toInput.closest('.border');
    expect(within(toField).getByText('($0.00)')).toBeInTheDocument();

    // Price impact is not calculated or displayed
    expect(screen.queryByText('Price Impact')).not.toBeInTheDocument();

    // Error is reported
    expect(reportException).toHaveBeenCalledTimes(1);
    expect(reportException).toHaveBeenCalledWith(mockError);
  });

  it('runs simulation and calculates price impact when from balance is insufficient, but displays error and does not calculate fees', async () => {
    getSimulation.mockResolvedValue({
      return_amount: '200000000' // 0.50 UST valuation
    });

    getBalance.mockResolvedValue(50 * 1e6);

    renderCard({ ustPrice: new Dec(0.49) });

    // Wait for balance
    await waitForBalances({ fromBalance: '50' });

    const fromInput = screen.getByLabelText('From');
    const toInput = screen.getByLabelText('To (estimated)');

    await act(async () => {
      // We need to delay between inputs otherwise we end up with a field value of "1"
      await userEvent.type(fromInput, '1000', { delay: 1 });
    });

    // "From" value is correctly converted to USD
    const fromField = fromInput.closest('.border');
    expect(within(fromField).getByText('($990.00)')).toBeInTheDocument(); // 1000 * 0.99

    // "To" value is properly set to value returned by simulation
    expect(toInput).toHaveDisplayValue('2000');

    // "To" value is correctly converted to USD
    const toField = toInput.closest('.border');
    expect(within(toField).getByText('($970.20)')).toBeInTheDocument(); // 2000 * 0.49 * .99

    // Simulated price is $0.01 higher than the spot price ($0.49),
    // so the price impact is $0.01/$0.49 = 0.0204
    expect(getDescriptionByTermEl(screen.getByText('Price Impact'))).toHaveTextContent('2.04%');

    expect(screen.queryByText('Not enough UST')).toBeInTheDocument();

    expect(getSimulation).toHaveBeenCalledWith(
      mockTerraClient,
      'terra1',
      new Int(1000000000),
      {
        native_token: {
          denom: 'uusd'
        }
      }
    );

    // Fees should have been estimated for each key stroke up until "10",
    // then "100" and "1000" exceeded the balance of 50
    expect(estimateFee).toHaveBeenCalledTimes(2);
  });

  it('displays pending state while waiting for tx to be mined', async () => {
    jest.useFakeTimers();

    // Simulation is performed on input change
    getSimulation.mockResolvedValue({
      return_amount: String(5 * 1e5)
    });

    // Before balances
    getBalance.mockResolvedValueOnce(2000000);
    getTokenBalance.mockResolvedValueOnce(0);

    // After balances
    getBalance.mockResolvedValueOnce(1000000);
    getTokenBalance.mockResolvedValueOnce(5 * 1e5);

    // Successful post
    postMsg.mockResolvedValue({ txhash: '123ABC' });

    // Stub out balance check
    sufficientBalance.mockResolvedValue(true);

    renderCard();

    // Initial balances
    await waitForBalances({ fromBalance: '2', toBalance: '0' });

    const fromInput = screen.getByLabelText('From');
    await act(async () => {
      await userEvent.type(fromInput, '1');
    });

    // Mock pending tx (404)
    mockTerraClient.tx.txInfo.mockRejectedValue();

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Swap' }));
    });

    expect(screen.getByText('Please Wait')).toBeInTheDocument();

    let txLink = screen.getByRole('link', { name: '123ABC' });
    expect(txLink).toBeInTheDocument();
    expect(txLink.getAttribute('href')).toEqual('https://finder.terra.money/testnet/tx/123ABC');

    // Mock mined tx
    mockTerraClient.tx.txInfo.mockResolvedValue({});

    // Blockchain is polled every 5s until tx is mined
    act(() => {
      jest.advanceTimersByTime(5000);
    });

    expect(await screen.findByText('Transaction Complete')).toBeInTheDocument();

    txLink = screen.getByRole('link', { name: '123ABC' });
    expect(txLink).toBeInTheDocument();
    expect(txLink.getAttribute('href')).toEqual('https://finder.terra.money/testnet/tx/123ABC');

    await act(async () => {
      await userEvent.click(screen.getByRole('button', { name: 'Continue' }));
    });

    // New balances
    await waitForBalances({ fromBalance: '1', toBalance: '5' });

    // Invokes callback
    expect(onSwapTxMined).toHaveBeenCalledTimes(1);
  });
});
Example #26
Source File: Tabs-test.js    From Lambda with MIT License 4 votes vote down vote up
describe('<Tabs />', () => {
  beforeEach(() => resetIdCounter());

  beforeAll(() => {
    // eslint-disable-next-line no-console
    console.error = (error, ...args) => {
      if (args.length > 0 && typeof error === 'string') {
        if (error.endsWith('%s%s')) {
          throw new Error(format(error.slice(0, -2), ...args.slice(0, -1)));
        }
        throw new Error(format(error, ...args));
      }
      throw new Error(error);
    };
  });

  describe('props', () => {
    test('should have sane defaults', () => {
      expectToMatchSnapshot(createTabs());
    });

    test('should honor positive defaultIndex prop', () => {
      expectToMatchSnapshot(createTabs({ defaultIndex: 1 }));
    });

    test('should honor negative defaultIndex prop', () => {
      expectToMatchSnapshot(createTabs({ defaultIndex: -1 }));
    });

    test('should call onSelect when selection changes', () => {
      const called = { index: -1, last: -1 };
      render(
        createTabs({
          onSelect(index, last) {
            called.index = index;
            called.last = last;
          },
        }),
      );

      userEvent.click(screen.getByTestId('tab2'));

      expect(called.index).toBe(1);
      expect(called.last).toBe(0);
    });

    test('should accept className', () => {
      expectToMatchSnapshot(createTabs({ className: 'foobar' }));
    });

    test('should accept domRef', () => {
      let domNode;
      render(
        createTabs({
          domRef: (node) => {
            domNode = node;
          },
        }),
      );

      expect(domNode).not.toBeUndefined();
      expect(domNode.className).toBe('react-tabs');
    });
  });

  describe('child props', () => {
    test('should reset ids correctly', () => {
      expectToMatchSnapshot(createTabs());

      resetIdCounter();

      expectToMatchSnapshot(createTabs());
    });
  });

  describe('interaction', () => {
    describe('mouse', () => {
      test('should update selectedIndex when clicked', () => {
        render(createTabs());
        userEvent.click(screen.getByTestId('tab2'));

        assertTabSelected(2);
      });

      test('should update selectedIndex when tab child is clicked', () => {
        render(createTabs());
        userEvent.click(screen.getByTestId('tab3'));

        assertTabSelected(3);
      });

      test('should not change selectedIndex when clicking a disabled tab', () => {
        render(createTabs({ defaultIndex: 0 }));
        userEvent.click(screen.getByTestId('tab4'));

        assertTabSelected(1);
      });
    });

    describe('keyboard', () => {
      test('should update selectedIndex when arrow right key pressed', () => {
        render(createTabs());
        const element = screen.getByTestId('tab1');
        userEvent.click(element);
        userEvent.type(element, '{arrowright}');

        assertTabSelected(2);
      });

      test('should update selectedIndex when arrow left key pressed (RTL)', () => {
        render(createTabs({ direction: 'rtl' }));
        const element = screen.getByTestId('tab1');
        userEvent.click(element);
        userEvent.type(element, '{arrowleft}');

        assertTabSelected(2);
      });

      test.skip('should not change selectedIndex when arrow left key pressed on a disabled tab', () => {
        render(createTabs());
        const element = screen.getByTestId('tab4');
        userEvent.click(element);
        userEvent.type(element, '{arrowleft}');

        assertTabSelected(1);
      });
    });
  });

  describe('performance', () => {
    test('should only render the selected tab panel', () => {
      render(createTabs());
      const tabPanels = screen.getAllByRole('tabpanel');

      expect(tabPanels[0]).toHaveTextContent('Hello Tab1');
      expect(tabPanels[1]).toHaveTextContent('');
      expect(tabPanels[2]).toHaveTextContent('');
      expect(tabPanels[3]).toHaveTextContent('');

      userEvent.click(screen.getByTestId('tab2'));

      expect(tabPanels[0]).toHaveTextContent('');
      expect(tabPanels[1]).toHaveTextContent('Hello Tab2');
      expect(tabPanels[2]).toHaveTextContent('');
      expect(tabPanels[3]).toHaveTextContent('');

      userEvent.click(screen.getByTestId('tab3'));

      expect(tabPanels[0]).toHaveTextContent('');
      expect(tabPanels[1]).toHaveTextContent('');
      expect(tabPanels[2]).toHaveTextContent('Hello Tab3');
      expect(tabPanels[3]).toHaveTextContent('');
    });

    test('should render all tabs if forceRenderTabPanel is true', () => {
      expectToMatchSnapshot(createTabs({ forceRenderTabPanel: true }));
    });
  });

  describe('validation', () => {
    test('should result with warning when tabs/panels are imbalanced', () => {
      expect(() =>
        render(
          <Tabs>
            <TabList>
              <Tab>Foo</Tab>
            </TabList>
          </Tabs>,
        ),
      ).toThrowErrorMatchingSnapshot();
    });

    test('should result with warning when tab outside of tablist', () => {
      expect(() =>
        render(
          <Tabs>
            <TabList>
              <Tab>Foo</Tab>
            </TabList>
            <Tab>Foo</Tab>
            <TabPanel />
            <TabPanel />
          </Tabs>,
        ),
      ).toThrowErrorMatchingSnapshot();
    });

    test('should result with warning when multiple tablist components exist', () => {
      expect(() =>
        render(
          <Tabs>
            <TabList>
              <Tab>Foo</Tab>
            </TabList>
            <TabList>
              <Tab>Foo</Tab>
            </TabList>
            <TabPanel />
            <TabPanel />
          </Tabs>,
        ),
      ).toThrowErrorMatchingSnapshot();
    });

    test('should result with warning when onSelect missing when selectedIndex set', () => {
      expect(() =>
        render(
          <Tabs selectedIndex={1}>
            <TabList>
              <Tab>Foo</Tab>
            </TabList>
            <TabPanel>Foo</TabPanel>
          </Tabs>,
        ),
      ).toThrowErrorMatchingSnapshot();
    });

    test('should result with warning when defaultIndex and selectedIndex set', () => {
      expect(() =>
        render(
          <Tabs selectedIndex={1} defaultIndex={1}>
            <TabList>
              <Tab>Foo</Tab>
            </TabList>
            <TabPanel>Foo</TabPanel>
          </Tabs>,
        ),
      ).toThrowErrorMatchingSnapshot();
    });

    test('should result with warning when tabs/panels are imbalanced and it should ignore non tab children', () => {
      expect(() =>
        render(
          <Tabs>
            <TabList>
              <Tab>Foo</Tab>
              <div>+</div>
            </TabList>

            <TabPanel>Hello Foo</TabPanel>
            <TabPanel>Hello Bar</TabPanel>
          </Tabs>,
        ),
      ).toThrowErrorMatchingSnapshot();
    });

    test('should allow random order for elements', () => {
      expectToMatchSnapshot(
        <Tabs forceRenderTabPanel>
          <TabPanel>Hello Foo</TabPanel>
          <TabList>
            <Tab>Foo</Tab>
            <Tab>Bar</Tab>
          </TabList>
          <TabPanel>Hello Bar</TabPanel>
        </Tabs>,
      );
    });

    test('should not throw a warning when wrong element is found', () => {
      expectToMatchSnapshot(
        <Tabs>
          <TabList>
            <Tab />
            <div />
          </TabList>
          <TabPanel />
        </Tabs>,
      );
    });

    test('should be okay with rendering without any children', () => {
      expectToMatchSnapshot(<Tabs />);
    });

    test('should be okay with rendering just TabList', () => {
      expectToMatchSnapshot(
        <Tabs>
          <TabList />
        </Tabs>,
      );
    });

    test('should gracefully render null', () => {
      expectToMatchSnapshot(
        <Tabs>
          <TabList>
            <Tab>Tab A</Tab>
            {false && <Tab>Tab B</Tab>}
          </TabList>
          <TabPanel>Content A</TabPanel>
          {false && <TabPanel>Content B</TabPanel>}
        </Tabs>,
      );
    });

    test('should support nested tabs', () => {
      render(
        <Tabs data-testid="first">
          <TabList>
            <Tab data-testid="tab1" />
            <Tab />
          </TabList>
          <TabPanel data-testid="panel1">
            Hello Tab1
            <Tabs data-testid="second">
              <TabList>
                <Tab />
                <Tab data-testid="tab2" />
              </TabList>
              <TabPanel />
              <TabPanel data-testid="panel2">Hello Tab2</TabPanel>
            </Tabs>
          </TabPanel>
          <TabPanel />
        </Tabs>,
      );

      userEvent.click(within(screen.getByTestId('second')).getByTestId('tab2'));

      assertTabSelected(1);
      assertTabSelected(2, within(screen.getByTestId('second')));
    });

    test('should allow other DOM nodes', () => {
      expectToMatchSnapshot(
        <Tabs>
          <div id="tabs-nav-wrapper">
            <button type="button">Left</button>
            <div className="tabs-container">
              <TabList>
                <Tab />
                <Tab />
              </TabList>
            </div>
            <button type="button">Right</button>
          </div>
          <div className="tab-panels">
            <TabPanel />
            <TabPanel />
          </div>
        </Tabs>,
      );
    });
  });

  test('should pass through custom properties', () => {
    expectToMatchSnapshot(<Tabs data-tooltip="Tooltip contents" />);
  });

  test('should not add known props to dom', () => {
    expectToMatchSnapshot(<Tabs defaultIndex={3} />);
  });

  test('should cancel if event handler returns false', () => {
    render(createTabs({ onSelect: () => false }));

    assertTabSelected(1);

    userEvent.click(screen.getByTestId('tab2'));
    assertTabSelected(1);

    userEvent.click(screen.getByTestId('tab3'));
    assertTabSelected(1);
  });

  test('should trigger onSelect handler when clicking', () => {
    let wasClicked = false;
    render(
      createTabs({
        onSelect: () => {
          wasClicked = true;
        },
      }),
    );

    assertTabSelected(1);

    userEvent.click(screen.getByTestId('tab2'));
    assertTabSelected(2);
    expect(wasClicked).toBe(true);
  });

  test('should trigger onSelect handler when clicking on open tab', () => {
    let wasClicked = false;
    render(
      createTabs({
        onSelect: () => {
          wasClicked = true;
        },
      }),
    );

    assertTabSelected(1);

    userEvent.click(screen.getByTestId('tab1'));
    assertTabSelected(1);
    expect(wasClicked).toBe(true);
  });

  test('should switch tabs if setState is called within onSelect', () => {
    class Wrap extends React.Component {
      state = {};

      handleSelect = () => this.setState({ foo: 'bar' });

      render() {
        const { foo } = this.state;
        return createTabs({
          onSelect: this.handleSelect,
          className: foo,
        });
      }
    }

    render(<Wrap />);

    userEvent.click(screen.getByTestId('tab2'));
    assertTabSelected(2);

    userEvent.click(screen.getByTestId('tab3'));
    assertTabSelected(3);
  });

  test('should allow for higher order components', () => {
    expectToMatchSnapshot(
      <Tabs>
        <TabListWrapper>
          <TabWrapper>Foo</TabWrapper>
          <TabWrapper>Bar</TabWrapper>
        </TabListWrapper>
        <TabPanelWrapper>Foo</TabPanelWrapper>
        <TabPanelWrapper>Bar</TabPanelWrapper>
      </Tabs>,
    );
  });

  test('should allow string children', () => {
    expectToMatchSnapshot(
      <Tabs>
        Foo
        <TabList>
          Foo
          <Tab>Foo</Tab>
          Foo
          <Tab>Bar</Tab>
          Foo
        </TabList>
        <TabPanel>Bar</TabPanel>
        <TabPanel>Foo</TabPanel>
        Foo
      </Tabs>,
    );
  });
});
Example #27
Source File: withHandlerGenerator.test.jsx    From covid with GNU General Public License v3.0 4 votes vote down vote up
test("withHandlerGenerator correctly generates a HOC to create a Wrapped component with data as a prop", async () => {
  // Generate a testing HOC
  const withIndex = (WrappedComponent, name = "index") =>
    withHandlerGenerator(
      withBackendHandlerHOC,
      ({ testParam }) => ({ testParam }),
      ({ testParam }, Handler, setIndex) => {
        const handler = new Handler(testParam);
        return handler.index(setIndex);
      },
      name,
      WrappedComponent
    );

  // Use the generated testing HOC to pass `index` as a prop
  const TestComponent = withIndex(
    ({ index: index_, role, testParam, ...props }) => {
      const { testParam: testParamIndex, ...index } = index_;
      return (
        <span role={role}>
          <span data-testid="index" {...index} />
          <span data-testid="testParam" value={testParam} />
          <span data-testid="testParamIndex" value={testParamIndex} />
        </span>
      );
    }
  );

  let rendered;

  await act(async () => {
    const paramValue = "test-value";
    rendered = render(
      <TestComponent role="test-component" testParam={paramValue} />
    );

    // Initial <Loading/> state
    const wrapperInitial = rendered.getByRole("wrapper");
    expect(wrapperInitial).toBeInTheDocument();

    const loading = within(wrapperInitial).getByRole("loading");
    expect(loading).toBeInTheDocument();

    await delay(20);

    // Final state, with `index` as a prop in the wrapped component
    const wrapper = rendered.getByRole("wrapper");
    expect(wrapper).toBeInTheDocument();

    const wrapped = within(wrapper).getByRole("test-component");
    expect(wrapped).toBeInTheDocument();

    const index = within(wrapped).getByRole("tested");
    expect(index).toBeInTheDocument();
    expect(index.getAttribute("data-testid")).toBe("index");

    const testParam = within(wrapped).getByTestId("testParam");
    expect(testParam).toBeInTheDocument();

    const testParamIndex = within(wrapped).getByTestId("testParamIndex");
    expect(testParamIndex).toBeInTheDocument();

    expect(testParamIndex.getAttribute("value")).toBe(paramValue);
    expect(testParamIndex.getAttribute("value")).toBe(
      testParam.getAttribute("value")
    );
  });

  await act(async () => {
    const paramValue = "test-value-2";
    rendered.rerender(
      <TestComponent role="test-component" testParam={paramValue} />
    );

    await delay(0);

    const testParam = rendered.getByTestId("testParam");
    expect(testParam).toBeInTheDocument();

    const testParamIndex = rendered.getByTestId("testParamIndex");
    expect(testParamIndex).toBeInTheDocument();

    expect(testParamIndex.getAttribute("value")).toBe(paramValue);
    expect(testParamIndex.getAttribute("value")).toBe(
      testParam.getAttribute("value")
    );
  });
});
Example #28
Source File: JobProfileDetails.test.js    From ui-data-export with Apache License 2.0 4 votes vote down vote up
describe('JobProfileDetails', () => {
  const stripes = {
    connect: Component => props => (
      <Component
        {... props}
        mutator={{}}
        resources={{}}
      />
    ),
  };
  const renderJobProfileDetails = () => {
    renderWithIntl(
      <SettingsComponentBuilder>
        <JobProfileDetails
          stripes={stripes}
          jobProfile={jobProfile}
          mappingProfile={mappingProfile}
          isDefaultProfile
          isProfileUsed
          onCancel={noop}
          onDelete={noop}
        />
      </SettingsComponentBuilder>,
      translationsProperties
    );
  };

  it('should display job profile details', () => {
    renderJobProfileDetails();

    const dialog = screen.getByRole('dialog');

    expect(dialog).toBeVisible();

    const headings = within(dialog).getAllByRole('heading', { name: jobProfile.name });

    headings.forEach(heading => expect(heading).toBeVisible());

    const summary = within(dialog).getByRole('region', { name: /summary/i });

    const labelsAndValues = [
      'Record created: 12/4/2018 11:22 AM',
      'Record last updated: 12/4/2018 1:28 PM',
      commonTranslations.name,
      jobProfile.name,
      translations.description,
      jobProfile.description,
      translations.mappingProfile,
      mappingProfile.name,
    ];

    labelsAndValues.forEach(el => expect(within(summary).getByText(el)).toBeVisible());
  });

  it('should display action buttons in the proper state', () => {
    renderJobProfileDetails();
    const actionButton = screen.getByText('Actions');

    userEvent.click(actionButton);

    const deleteButton = screen.getByText(commonTranslations.delete);
    const duplicateButton = screen.getByText(commonTranslations.duplicate);
    const editButton = screen.getByText(commonTranslations.edit);

    expect(deleteButton).toBeEnabled();
    expect(duplicateButton).toBeEnabled();
    expect(editButton).toBeEnabled();
  });

  describe('rendering details without description for a job profile which is not already in use', () => {
    const renderJobProfileWitoutDescription = () => {
      renderWithIntl(
        <SettingsComponentBuilder>
          <JobProfileDetails
            stripes={stripes}
            jobProfile={{
              ...jobProfile,
              description: null,
            }}
            mappingProfile={mappingProfile}
            isDefaultProfile={false}
            isProfileUsed={false}
            onCancel={noop}
          />
        </SettingsComponentBuilder>,
        translationsProperties
      );
    };

    it('should display no value in description', () => {
      renderJobProfileWitoutDescription();
      const description = document.querySelector('[data-test-job-profile-description]');

      expect(within(description).getByText('-')).toBeVisible();
    });

    it('should display action buttons in the proper state', () => {
      renderJobProfileWitoutDescription();
      const actionButton = screen.getByText('Actions');

      userEvent.click(actionButton);

      const deleteButton = screen.getByText(commonTranslations.delete);
      const duplicateButton = screen.getByText(commonTranslations.duplicate);
      const editButton = screen.getByText(commonTranslations.edit);

      expect(deleteButton).toBeEnabled();
      expect(duplicateButton).toBeEnabled();
      expect(editButton).toBeEnabled();
    });

    describe('clicking on delete profiles button', () => {
      it('should display delete confirmation modal', async () => {
        renderJobProfileWitoutDescription();
        const actionButton = screen.getByText('Actions');

        userEvent.click(actionButton);

        const deleteButton = screen.getByText(commonTranslations.delete);

        userEvent.click(deleteButton);

        const modal = screen.getAllByRole('dialog').find(dialog => within(dialog).getByRole('heading', { name: /delete/i }));

        expect(modal).toBeVisible();
        userEvent.click(within(modal).getByRole('button', { name: /cancel/i }));

        await waitForElementToBeRemoved(modal);
      });
    });
  });

  describe('rendering job profile details in loading state', () => {
    const renderJobProfileWithLoading = () => {
      renderWithIntl(
        <SettingsComponentBuilder>
          <JobProfileDetails
            stripes={stripes}
            isLoading
            isDefaultProfile={false}
            isProfileUsed
            onCancel={noop}
          />
        </SettingsComponentBuilder>,
        translationsProperties
      );
    };

    it('should display preloader', () => {
      renderJobProfileWithLoading();
      expect(document.querySelector('[data-test-preloader]')).toBeVisible();
    });
  });
});
Example #29
Source File: JobProfileDetailsRoute.test.js    From ui-data-export with Apache License 2.0 4 votes vote down vote up
describe('JobProfileDetails', () => {
  let server;

  beforeEach(() => {
    server = new Pretender();
  });

  afterEach(() => {
    server.shutdown();
  });

  describe('rendering details for a job profile without job profile data', () => {
    it('should display preloader', async () => {
      server.get('/data-export/mapping-profiles/:id', () => [
        200,
        { 'content-type': 'application/json' },
        JSON.stringify(mappingProfile),
      ]);
      setupJobProfileDetailsRoute();

      const dialog = screen.getByRole('dialog');

      expect(dialog).toBeVisible();
      expect(document.querySelector('[data-test-preloader]')).toBeVisible();
    });

    it('should history includes location.search', () => {
      server.get('/data-export/mapping-profiles/:id', () => [
        200,
        { 'content-type': 'application/json' },
        JSON.stringify(mappingProfile),
      ]);
      setupJobProfileDetailsRoute();

      const cancelButton = screen.getByRole('button', { name: /cancel/i });

      expect(cancelButton).toBeEnabled();

      userEvent.click(cancelButton);

      expect(history.some(el => el.includes('?location'))).toBeTruthy();
    });
  });

  describe('rendering details for a job profile without mapping profile data', () => {
    it('should display preloader', async () => {
      server.get('/data-export/job-profiles/:id', () => [
        200,
        { 'content-type': 'application/json' },
        JSON.stringify(jobProfile),
      ]);
      setupJobProfileDetailsRoute({ matchParams: { id: JOB_PROFILE_ID } });

      expect(document.querySelector('[data-test-preloader]')).toBeVisible();
    });
  });

  describe('rendering details for a job with mapping profile', () => {
    it('should display preloader for default job profile', async () => {
      server.get('/data-export/job-profiles/:id', () => [
        200,
        { 'content-type': 'application/json' },
        JSON.stringify(jobProfile),
      ]);
      server.get('/data-export/mapping-profiles/:id', () => [
        200,
        { 'content-type': 'application/json' },
        JSON.stringify(mappingProfile),
      ]);

      setupJobProfileDetailsRoute({ matchParams: { id: JOB_PROFILE_ID } });

      expect(document.querySelector('[data-test-preloader]')).toBeVisible();
    });
  });

  describe('rendering details for non default job profile without job execution data', () => {
    const nonDefaultJobProfileId = 'job-profile-id';

    it('should display job profile details for non default job profile', async () => {
      server.get('/data-export/job-profiles/:id', () => [
        200,
        { 'content-type': 'application/json' },
        JSON.stringify({
          ...jobProfile,
          id: nonDefaultJobProfileId,
        }),
      ]);
      server.get('/data-export/mapping-profiles/:id', () => [
        200,
        { 'content-type': 'application/json' },
        JSON.stringify(mappingProfile),
      ]);
      setupJobProfileDetailsRoute({ matchParams: { id: nonDefaultJobProfileId } });

      const summary = await screen.findByRole('region', { name: /summary/i });

      const labelsAndValues = [
        'Record created: 12/4/2018 11:22 AM',
        'Record last updated: 12/4/2018 1:28 PM',
        jobProfile.name,
        jobProfile.description,
        mappingProfile.name,
      ];

      labelsAndValues.forEach(el => expect(within(summary).getByText(el)).toBeVisible());
    });
  });

  describe('rendering details for default job profile with job execution data', () => {
    it('should display job profile details', async () => {
      server.get('/data-export/job-profiles/:id', () => [
        200,
        { 'content-type': 'application/json' },
        JSON.stringify(jobProfile),
      ]);
      server.get('/data-export/mapping-profiles/:id', () => [
        200,
        { 'content-type': 'application/json' },
        JSON.stringify(mappingProfile),
      ]);

      setupJobProfileDetailsRoute();

      const summary = await screen.findByRole('region', { name: /summary/i });

      const dialog = screen.getByRole('dialog');

      const headings = within(dialog).getAllByRole('heading', { name: jobProfile.name });

      headings.forEach(heading => expect(heading).toBeVisible());

      const labelsAndValues = [
        'Record created: 12/4/2018 11:22 AM',
        'Record last updated: 12/4/2018 1:28 PM',
        jobProfile.name,
        jobProfile.description,
        mappingProfile.name,
      ];

      labelsAndValues.forEach(el => expect(within(summary).getByText(el)).toBeVisible());
    });
  });
});