@smartive/xstate-test-toolbox
    TypeScript icon, indicating that this package has built-in type declarations

    2.0.2 • Public • Published

    @smartive/xstate-test-toolbox

    This package contains the helper createTestPlans which can be used with xstate and @xstate/test.

    createTestPlans

    This function adds the meta-property to every state and a test if it is defined within tests. (see in example) Beside that it generates all possible test simple path plans for all possible combinations of your guards.

    ⚠️ Attention: Your statechart must consist of only string references to guards, actions and services otherwise the testing will break.

    Example

    // The following snippet does not include all needed imports and code it is intended
    // to give you a starting point and an idea how the `createTestPlans`-function can be used.
    
    import { createTestPlans, StatesTestFunctions } from '@smartive/xstate-test-toolbox';
    import { FetchInterceptor, mockHeaders, mockResponse, RequestCallCountMock } from '@smartive/testcafe-utils';
    import { TestEventsConfig } from '@xstate/test/lib/types';
    import { RequestMock } from 'testcafe';
    import { Context, machine } from './machine-under-test';
    // ...
    
    type TestContext = {
      t: TestController,
      plan: string,
      path: string
    };
    
    const fetchInterceptor = new FetchInterceptor({
      fetchPeople: /.+swapi\.dev.+\/people\/$/,
      fetchMore: /.+swapi\.dev.+\/people\/\?page=.+/,
      searchPeople: /.+swapi\.dev.+\/people\/\?search=.+/,
    });
    
    const getRequestMocks = (plan: string, path: string): object[] => {
      const peopleUrl = /.+swapi\.dev.+\/people\/.*/
      if (
        plan.includes('NoResults') ||
        (plan.includes('Searching') && path.includes('NoResults'))
      ) {
        return [
          RequestMock()
            .onRequestTo(peopleUrl)
            .respond(empty, 200, mockHeaders),
        ];
      }
    
      if (plan.includes('Error')) {
        switch (path) {
          case 'Pending → error.platform.fetchPeople':
            return [
              RequestMock().onRequestTo(peopleUrl).respond({}, 400, mockHeaders),
            ];
          case 'Pending → done.invoke.fetchPeople → Idle → END_REACHED → LoadingMore → error.platform.fetchMore':
            return [
              new RequestCallCountMock(peopleUrl, [
                { body: mockResponse(peoples) },
                { body: mockResponse({}, 400) },
              ]),
            ];
          case 'Pending → done.invoke.fetchPeople → NoResults → QUERY_DISPATCHED → Searching → error.platform.searchPeople':
            return [
              RequestMock()
                .onRequestTo(fetchInterceptor.interceptUrls.searchPeople)
                .respond({}, 400, mockHeaders),
              RequestMock()
                .onRequestTo(peopleUrl)
                .respond(empty, 200, mockHeaders),
            ];
          case 'Pending → done.invoke.fetchPeople → Idle → QUERY_DISPATCHED → Searching → error.platform.searchPeople':
            return [
              RequestMock()
                .onRequestTo(fetchInterceptor.interceptUrls.searchPeople)
                .respond({}, 400, mockHeaders),
            ];
        }
      }
    
      return [];
    };
    
    const tests: StatesTestFunctions<Context, TestContext> = {
      Pending: ({ t }) => t.expect(page.spinner.exists).ok(),
      Idle: ({ t }) => t.expect(page.listItem.count).gt(0),
      LoadingMore: ({ t }) => t.expect(page.listItem.count).gt(1).expect(page.spinner.exists).ok(),
      Error: ({ t }) => t.expect(page.error.exists).ok(),
      NoResults: ({ t }) => t.expect(page.notify.exists).ok(),
      Searching: ({ t }) => t.expect(page.search.value).contains('luke').expect(page.spinner.exists).ok(),
    };
    
    const testEvents: TestEventsConfig<TestContext> = {
      END_REACHED: ({ t }) => t.hover(page.listItem.nth(9), { speed: 0.8 }),
      QUERY_DISPATCHED: ({ t }) => t.typeText(page.search, 'luke', { speed: 0.8 }),
      'done.invoke.fetchPeople': fetchInterceptor.resolve('fetchPeople'),
      'error.platform.fetchPeople': fetchInterceptor.resolve('fetchPeople'),
      'error.platform.fetchMore': fetchInterceptor.resolve('fetchMore'),
      'error.platform.searchPeople': fetchInterceptor.resolve('searchPeople'),
    };
    
    createTestPlans({
      machine,
      tests,
      testEvents,
      // add logLevel: LogLevel.INFO for some output which plans/paths are generated
    }).forEach(
      ({ description: plan, paths }) => {
        fixture(plan).page(`http://localhost:3000/peoples`);
    
        paths.forEach(({ test: run, description: path }) => {
          test
            .clientScripts([fetchInterceptor.clientScript()])
            .requestHooks(getRequestMocks(plan, path))(`via ${path} ⬏`, (t) => run({ plan, path, t }));
        });
      }
    );

    Install

    npm i @smartive/xstate-test-toolbox

    DownloadsWeekly Downloads

    2

    Version

    2.0.2

    License

    MIT

    Unpacked Size

    14.8 kB

    Total Files

    6

    Last publish

    Collaborators

    • smartive-ci
    • mfeltscher
    • petermanser
    • cbuehler
    • dwirz
    • deniaz
    • nmaro