jest-when#when TypeScript Examples

The following examples show how to use jest-when#when. 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: gitutils.test.ts    From bedrock-cli with MIT License 7 votes vote down vote up
describe("tryGetGitOrigin", () => {
  afterEach(() => {
    delete process.env.APP_REPO_URL;
  });

  it("attempts to retrieve azdo git origin", async () => {
    const originUrl = "http://github.com/repo/url";
    process.env.APP_REPO_URL = originUrl;

    const originUrlResponse = await tryGetGitOrigin();
    expect(originUrlResponse).toEqual(originUrl);
  });

  it("attempts to retrieve git origin from using git cli", async () => {
    const originUrl = "http://github.com/repo/url";
    // Echoing variable from AzDo should fail trying Git
    delete process.env.APP_REPO_URL;

    // Retrieving url from Git succeeds
    when(exec as jest.Mock)
      .calledWith("git", ["config", "--get", "remote.origin.url"])
      .mockReturnValue(originUrl);

    const originUrlResponse = await tryGetGitOrigin();
    expect(originUrlResponse).toEqual(originUrl);
  });
});
Example #2
Source File: utils.mock.ts    From gitlab-ci-local with MIT License 6 votes vote down vote up
export function initBashSpyReject(spyMocks: {cmd: string; rejection: string}[]) {
    const spyOn = jest.spyOn(Utils, "bash");

    for (const spyMock of spyMocks) {
        when(spyOn).calledWith(spyMock.cmd, expect.any(String)).mockRejectedValue(new Error(spyMock.rejection));
    }
}
Example #3
Source File: utils.mock.ts    From gitlab-ci-local with MIT License 6 votes vote down vote up
export function initBashSpy(spyMocks: {cmd: string; returnValue: any}[]) {
    const spyOn = jest.spyOn(Utils, "bash");

    for (const spyMock of spyMocks) {
        when(spyOn).calledWith(spyMock.cmd, expect.any(String)).mockResolvedValue(spyMock.returnValue);
    }
}
Example #4
Source File: utils.mock.ts    From gitlab-ci-local with MIT License 6 votes vote down vote up
export function initSpawnSpy(spyMocks: {cmdArgs: string[]; returnValue: any}[]) {
    const spyOn = jest.spyOn(Utils, "spawn");

    for (const spyMock of spyMocks) {
        when(spyOn).calledWith(spyMock.cmdArgs, expect.any(String)).mockResolvedValue(spyMock.returnValue);
    }
}
Example #5
Source File: useRouteRedirects.test.ts    From oasis-wallet-web with Apache License 2.0 6 votes vote down vote up
describe('useRouteRedirects', () => {
  beforeEach(() => {})

  it('should redirects to account page', () => {
    when(useSelector as any)
      .calledWith(selectAddress)
      .mockReturnValue('dummyAddress')
      .calledWith(selectActiveWalletId)
      .mockReturnValue(0)

    renderHook(() => useRouteRedirects())

    expect(mockedHistoryPush).toHaveBeenCalledWith('/account/dummyAddress')
  })

  it('should not trigger redirect when address is not defined', () => {
    when(useSelector as any)
      .calledWith(selectAddress)
      .mockReturnValue('')
      .calledWith(selectActiveWalletId)
      .mockReturnValue(1)

    renderHook(() => useRouteRedirects())

    expect(mockedHistoryPush).not.toHaveBeenCalled()
  })

  it('should not trigger redirect when active wallet id is missing', () => {
    when(useSelector as any)
      .calledWith(selectAddress)
      .mockReturnValue('dummyAddress')
      .calledWith(selectActiveWalletId)
      .mockReturnValue(undefined)

    renderHook(() => useRouteRedirects())

    expect(mockedHistoryPush).not.toHaveBeenCalled()
  })
})
Example #6
Source File: gitutils.test.ts    From bedrock-cli with MIT License 6 votes vote down vote up
describe("getOriginUrl", () => {
  it("should call exec with the proper git arguments", async () => {
    const originUrl = "foo";

    when(exec as jest.Mock)
      .calledWith("git", ["config", "--get", "remote.origin.url"])
      .mockReturnValue(originUrl);

    const originUrlResponse = await getOriginUrl();

    expect(originUrlResponse).toEqual(originUrl);
    expect(exec).toHaveBeenCalledTimes(1);
    expect(exec).toHaveBeenCalledWith(
      "git",
      ["config", "--get", "remote.origin.url"],
      { cwd: "." }
    );
  });

  it("should call exec with the proper git arguments with a repo path", async () => {
    const originUrl = "foo";
    const repoPath = "/repo/path";

    when(exec as jest.Mock)
      .calledWith("git", ["config", "--get", "remote.origin.url"], {
        cwd: repoPath,
      })
      .mockReturnValue(originUrl);

    const originUrlResponse = await getOriginUrl(repoPath);

    expect(originUrlResponse).toEqual(originUrl);
    expect(exec).toHaveBeenCalledTimes(1);
    expect(exec).toHaveBeenCalledWith(
      "git",
      ["config", "--get", "remote.origin.url"],
      { cwd: repoPath }
    );
  });

  it("should return an error when exec throws an error", async () => {
    (exec as jest.Mock).mockImplementation(() => {
      throw new Error("sample error.");
    });

    let error: Error | undefined;
    try {
      await getOriginUrl();
    } catch (_) {
      error = _;
    }

    expect(error).not.toBeUndefined();
  });
});
Example #7
Source File: BadgeDetail.test.tsx    From crowdsource-dataplatform with MIT License 5 votes vote down vote up
describe('BadgeDetail', () => {
  const setup = () => {
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'English');

    when(sessionStorage.getItem)
      .calledWith('prevPath')
      .mockImplementation(() => '/tts-initiative');

    return render(<BadgeDetail />);
  };

  it('should render the component and matches it against stored snapshot', () => {
    const { asFragment } = setup();

    expect(asFragment()).toMatchSnapshot();
  });

  it('should render badges in "Assamese" language when Assamese is chosen from language dropdown', async () => {
    setup();

    userEvent.selectOptions(screen.getByTestId('SelectDropDownLanguage'), 'অসমীয়া');

    expect(screen.getByRole('combobox', { name: 'Your Language' })).toHaveValue('Assamese');
  });

  it('should render badge detail for selected initiative', async () => {
    let scrollIntoViewMock = jest.fn();
    window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;

    setup();
    userEvent.click(screen.getByRole('tab', { name: 'asr initiativeTextSuffix' }));

    expect(scrollIntoViewMock).toBeCalled();
    userEvent.click(screen.getByRole('tab', { name: 'asr initiativeTextSuffix' }));
    expect(screen.getByRole('tab', { name: 'asr initiativeTextSuffix' })).toHaveClass('active');
  });

  it('should render badge detail for selected initiative when comes from thank you page', async () => {
    let scrollIntoViewMock = jest.fn();
    window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;

    setup();

    await waitFor(() => expect(scrollIntoViewMock).toBeCalled());

    expect(screen.getByRole('tab', { name: 'asr initiativeTextSuffix' })).toHaveClass('active');
  });

  it('should activate silver badges when silver medal is selected', async () => {
    await setup();
    expect(screen.getByText('Silver')).toBeInTheDocument();
    expect(screen.getByText('Silver').parentElement).not.toHaveClass('active');
    userEvent.click(screen.getByText('Silver'));
    await waitFor(() => {
      expect(screen.getByText('Silver').parentElement).toHaveClass('active');
    });
  });

  it('should activate validate badges when validate radio button is selected', async () => {
    await setup();
    expect(screen.getByTestId('action2')).not.toBeChecked();
    userEvent.click(screen.getByTestId('action2'));
    expect(screen.getByTestId('action2')).toBeChecked();
    expect(screen.getByTestId('action1')).not.toBeChecked();
  });
});
Example #8
Source File: useConsumerGroupsOffsetsForEntity.test.tsx    From backstage with Apache License 2.0 5 votes vote down vote up
describe('useConsumerGroupOffsets', () => {
  const entity: Entity = {
    apiVersion: 'v1',
    kind: 'Component',
    metadata: {
      name: 'test',
      annotations: {
        'kafka.apache.org/consumer-groups': `prod/${consumerGroupOffsets.consumerId}`,
      },
    },
    spec: {
      owner: 'guest',
      type: 'Website',
      lifecycle: 'development',
    },
  };

  const wrapper = ({ children }: PropsWithChildren<{}>) => {
    return (
      <TestApiProvider
        apis={[
          [errorApiRef, mockErrorApi],
          [kafkaApiRef, mockKafkaApi],
        ]}
      >
        <EntityProvider entity={entity}>{children}</EntityProvider>
      </TestApiProvider>
    );
  };

  const subject = () =>
    renderHook(useConsumerGroupsOffsetsForEntity, { wrapper });

  it('returns correct consumer group for annotation', async () => {
    mockKafkaApi.getConsumerGroupOffsets.mockResolvedValue(
      consumerGroupOffsets,
    );
    when(mockKafkaApi.getConsumerGroupOffsets)
      .calledWith('prod', consumerGroupOffsets.consumerId)
      .mockResolvedValue(consumerGroupOffsets);

    const { result, waitForNextUpdate } = subject();
    await waitForNextUpdate();
    const [tableProps] = result.current;

    expect(tableProps.consumerGroupsTopics).toStrictEqual([
      {
        clusterId: 'prod',
        consumerGroup: consumerGroupOffsets.consumerId,
        topics: consumerGroupOffsets.offsets,
      },
    ]);
  });

  it('posts an error to the error api', async () => {
    const error = new Error('error!');
    mockKafkaApi.getConsumerGroupOffsets.mockRejectedValueOnce(error);

    const { waitForNextUpdate } = subject();
    await waitForNextUpdate();

    expect(mockErrorApi.post).toHaveBeenCalledWith(error);
  });
});
Example #9
Source File: ActionCard.test.tsx    From crowdsource-dataplatform with MIT License 5 votes vote down vote up
describe('ActionCard', () => {
  const setup = () => {
    router.locale = 'as';
    return render(
      <ActionCard
        icon="some-icon.svg"
        type="contribute"
        text="some-text"
        initiative="tts"
        warningMsg="Only contributions invited for the selected language"
        altText="Contribute"
      />
    );
  };

  verifyAxeTest(setup());

  it('should render the component and match it against stored snapshot', () => {
    const { asFragment } = setup();

    expect(asFragment()).toMatchSnapshot();
  });

  it('should show the user detail modal when user not registered', async () => {
    setup();

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

    await waitFor(() => expect(screen.getByTestId('ChangeUserForm')).toBeInTheDocument());

    userEvent.click(screen.getByRole('button', { name: 'Close' }));

    await waitForElementToBeRemoved(() => screen.queryByTestId('ChangeUserModal'));

    expect(screen.queryByTestId('ChangeUserModal')).not.toBeInTheDocument();
  });

  it('should not show the userdetail modal when user detail is present in local storage', async () => {
    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(
        () => '{"userName":"abc","motherTongue":"","age":"","gender":"","language":"English","toLanguage":""}'
      );

    setup();

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

    expect(screen.queryByTestId('ChangeUserModal')).not.toBeInTheDocument();
  });
});
Example #10
Source File: update.test.ts    From joplin-plugin-note-overview with MIT License 5 votes vote down vote up
describe("noteoverview.update", function () {
  beforeEach(async () => {
    jest.spyOn(logging, "silly").mockImplementation(() => {});
    jest.spyOn(logging, "verbose").mockImplementation(() => {});
    jest.spyOn(logging, "info").mockImplementation(() => {});
  });

  afterEach(async () => {
    jest.spyOn(logging, "silly").mockReset();
    jest.spyOn(logging, "verbose").mockReset();
    jest.spyOn(logging, "info").mockReset();
  });

  it(`Check calls of getOverviewContent function`, async () => {
    /* prettier-ignore */
    const testCases = [
        { noteid: "simpleEmpty", expected: 1, },
        { noteid: "simple", expected: 1, },
        { noteid: "multipleEmpty", expected: 3, },
      ];

    const spyOnegetOverviewContent = jest.spyOn(
      noteoverview,
      "getOverviewContent"
    );
    jest
      .spyOn(joplin.workspace, "selectedNote")
      .mockImplementation(() => Promise.resolve("someSelectedNote"));
    const spyOnJoplinDataGet = jest.spyOn(joplin.data, "get");

    for (const testCase of testCases) {
      spyOnJoplinDataGet.mockReset();
      /* prettier-ignore */
      when(spyOnJoplinDataGet)
          .mockImplementation(() => Promise.resolve("no mockImplementation"))
          .calledWith(expect.arrayContaining(["notes", testCase.noteid]),expect.anything())
            .mockImplementation(() => Promise.resolve( getNote(testCase.noteid) ));

      // check calls to getOverviewContent
      await noteoverview.update(testCase.noteid, false);
      expect(spyOnegetOverviewContent).toBeCalledTimes(testCase.expected);
      spyOnegetOverviewContent.mockClear();
    }
  });
});
Example #11
Source File: pw.test.ts    From joplin-plugin-backup with MIT License 5 votes vote down vote up
describe("Password", function () {
  beforeEach(async () => {
    backup = new Backup() as any;
  });

  it(`Check`, async () => {
    const spyOnsSettingsValue = jest.spyOn(joplin.settings, "value");
    const spyOnsSettingsSetValue = jest.spyOn(joplin.settings, "setValue");

    const testCases = [
      {
        usePassword: false,
        password: "",
        passwordRepeat: "",
        expected: 0,
        called: 2,
      },
      {
        usePassword: false,
        password: "test",
        passwordRepeat: "test",
        expected: 0,
        called: 2,
      },
      {
        usePassword: false,
        password: "testA",
        passwordRepeat: "testB",
        expected: 0,
        called: 2,
      },
      {
        usePassword: true,
        password: "test",
        passwordRepeat: "test",
        expected: 1,
        called: 0,
      },
      {
        usePassword: true,
        password: "testA",
        passwordRepeat: "testB",
        expected: -1,
        called: 2,
      },
      {
        usePassword: true,
        password: " ",
        passwordRepeat: " ",
        expected: -1,
        called: 2,
      },
      {
        usePassword: true,
        password: "",
        passwordRepeat: " ",
        expected: -1,
        called: 2,
      },
    ];

    for (const testCase of testCases) {
      /* prettier-ignore */
      when(spyOnsSettingsValue)
        .mockImplementation(() => Promise.resolve("no mockImplementation"))
        .calledWith("usePassword").mockImplementation(() => Promise.resolve(testCase.usePassword))
        .calledWith("password").mockImplementation(() => Promise.resolve(testCase.password))
        .calledWith("passwordRepeat").mockImplementation(() => Promise.resolve(testCase.passwordRepeat));
      expect(await backup.checkPassword()).toBe(testCase.expected);

      await backup.enablePassword();
      expect(spyOnsSettingsSetValue).toBeCalledTimes(testCase.called);
      spyOnsSettingsSetValue.mockReset();
    }
  });
});
Example #12
Source File: TtsDashboard.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('TtsDashboard', () => {
  global.document.getElementById = jest.fn().mockImplementation(
    x =>
      x === 'float' && {
        style: {
          width: '50%',
        },
      }
  );

  const setup = async () => {
    fetchMock.doMockIf('/aggregated-json/cumulativeDataByLanguage.json').mockResponse(
      JSON.stringify([
        {
          language: 'English',
          total_contribution_count: 36,
          total_contributions: 0.057,
          total_speakers: 9,
          total_validation_count: 2,
          total_validations: 0.001,
          type: 'asr',
        },
      ])
    );
    const renderResult = render(
      <SWRConfig value={{ provider: () => new Map() }}>
        <TtsDashboard />
      </SWRConfig>
    );
    await screen.findByText('ContributionStats');
    return renderResult;
  };
  it('should contain language selector', async () => {
    await setup();
    expect(screen.getByRole('combobox', { name: 'Select Language' })).toBeInTheDocument();
  });

  it('changing language from language selector should update stats', async () => {
    await setup();
    expect(screen.getByRole('combobox', { name: 'Select Language' })).toBeInTheDocument();
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'English');
    await waitForElementToBeRemoved(() => screen.queryAllByTestId('Loader'));
    expect(fetchMock).toBeCalledWith('/aggregated-json/cumulativeDataByLanguage.json');
    expect(screen.queryByText('languages')).not.toBeInTheDocument();
  });

  it('changing language from language selector should display nodata message when data not available', async () => {
    await setup();
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'English');
    await waitForElementToBeRemoved(() => screen.queryAllByTestId('Loader'));
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'Bengali');
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/aggregated-json/cumulativeDataByLanguage.json');
    });
    await waitFor(() => {
      expect(screen.getByText('noDataMessageDashboard')).toBeInTheDocument();
    });
    await waitFor(() => expect(screen.queryByText('noDataMessageDashboard')).not.toBeInTheDocument());
    expect(screen.queryByText('languages')).not.toBeInTheDocument();
  });

  it('changing to language where data not available and clicking contribute now should display change user modal for new user', async () => {
    await setup();
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'Bengali');
    await waitFor(() => {
      expect(screen.getByText('noDataMessageDashboard')).toBeInTheDocument();
    });
    userEvent.click(screen.getByRole('button', { name: 'contributeNow' }));
    await waitFor(() => expect(screen.getByTestId('ChangeUserForm')).toBeInTheDocument());

    userEvent.click(screen.getByRole('button', { name: 'Close' }));

    await waitForElementToBeRemoved(() => screen.queryByTestId('ChangeUserModal'));
  });

  it('changing to language where data not available and clicking contribute now should redirect for existing user', async () => {
    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(
        () => '{"userName":"abc","motherTongue":"","age":"","gender":"","language":"English","toLanguage":""}'
      );
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'English');
    await setup();
    await waitFor(() => {
      expect(localStorage.getItem).toBeCalled();
    });
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'Bengali');
    await waitFor(() => {
      expect(screen.getByText('noDataMessageDashboard')).toBeInTheDocument();
    });
    userEvent.click(screen.getByRole('button', { name: 'contributeNow' }));
    await waitFor(() => expect(screen.queryByTestId('ChangeUserModal')).not.toBeInTheDocument());
  });
});
Example #13
Source File: TtsTranscribe.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('TtsTranscribe', () => {
  const resultData = {
    data: [
      {
        dataset_row_id: 1248671,
        media_data:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/2_3_Regional-Kohima-English-0725-20198228349.wav',
        source_info:
          '["newsonair.nic.in", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3"]',
      },
      {
        dataset_row_id: 1248672,
        media_data:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/2_3_Regional-Kohima-English-0725-20198228349.wav',
        source_info:
          '["newsonair.nic.in", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3"]',
      },
      {
        dataset_row_id: 1248673,
        media_data:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/2_3_Regional-Kohima-English-0725-20198228349.wav',
        source_info:
          '["newsonair.nic.in", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3"]',
      },
      {
        dataset_row_id: 1248674,
        media_data:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/2_3_Regional-Kohima-English-0725-20198228349.wav',
        source_info:
          '["newsonair.nic.in", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3"]',
      },
      {
        dataset_row_id: 1248675,
        media_data:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/2_3_Regional-Kohima-English-0725-20198228349.wav',
        source_info:
          '["newsonair.nic.in", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3", "http://newsonair.nic.in/writereaddata/Bulletins_Audio/Regional/2019/Aug/Regional-Kohima-English-0725-20198228349.mp3"]',
      },
    ],
  };
  const setup = async (resultData: any) => {
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'Hindi');

    const locationInfo = {
      country: 'India',
      regionName: 'National Capital Territory of Delhi',
    };

    when(localStorage.getItem)
      .calledWith('locationInfo')
      .mockImplementation(() => JSON.stringify(locationInfo));

    const speakerDetails = {
      userName: 'abc',
      motherTongue: '',
      age: '',
      gender: '',
      language: 'Hindi',
      toLanguage: '',
    };

    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(() => JSON.stringify(speakerDetails));

    fetchMock.doMockOnceIf('/media/asr').mockResponseOnce(JSON.stringify(resultData));
    const renderResult = render(
      <>
        <TtsTranscribe />
        <div id="report">
          <button>Stop Audio</button>
        </div>
      </>
    );

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/media/asr', {
        body: JSON.stringify({
          language: 'Hindi',
          userName: 'abc',
        }),
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
      });
    });

    return renderResult;
  };

  it('play button click should play audio and pause button should be enabled', async () => {
    await setup(resultData);

    expect(screen.getByRole('textbox', { name: 'addText (hindi)' })).toBeDisabled();

    expect(screen.getByRole('img', { name: 'Play Icon' })).toBeInTheDocument();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument();

    expect(screen.getByRole('textbox', { name: 'addText (hindi)' })).toBeEnabled();
  });

  it('should show the thank you message when no data present', async () => {
    const result = { data: [] };
    await setup(result);

    await waitFor(() => {
      expect(screen.getByText('ttsContributeNoDataThankYouMessage')).toBeInTheDocument();
    });
  });

  it('should show the error popup for 1st sentence when api throw the error and close modal on clicking button', async () => {
    const url = '/media/asr';
    const errorResponse = new Error('Some error');
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);
    render(<TtsTranscribe />);
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/media/asr', {
        body: JSON.stringify({
          language: 'Hindi',
          userName: 'abc',
        }),
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
      });
    });

    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(screen.queryByText('apiFailureError')).not.toBeInTheDocument();
    });
  });

  it('should show the error popup for 2nd sentence when api throw the error and modal should close on clicking button', async () => {
    const url = '/skip';
    const errorResponse = new Error('Some error');
    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/media/asr', {
        body: JSON.stringify({
          language: 'Hindi',
          userName: 'abc',
        }),
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
      });
    });

    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(screen.queryByText('apiFailureError')).not.toBeInTheDocument();
    });
  });

  it('pause button click should pause audio and play button should be enabled', async () => {
    await setup(resultData);

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument();

    userEvent.click(screen.getByRole('img', { name: 'Pause Icon' }));

    expect(screen.getByRole('img', { name: 'Play Icon' })).toBeInTheDocument();
  });

  it('should abort the audio when user clicks on report, test speaker, feedback button', async () => {
    await setup(resultData);

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    userEvent.click(screen.getByRole('button', { name: /Stop Audio/ }));

    await waitFor(() => {
      expect(screen.getByRole('img', { name: 'Play Icon' })).toBeInTheDocument();
    });
  });

  it('should test the textarea text with valid language', async () => {
    await setup(resultData);

    userEvent.type(screen.getByRole('textbox', { name: 'addText (hindi)' }), 'बपपप');

    await waitFor(() => {
      expect(screen.queryByText('Please type in your chosen language')).not.toBeInTheDocument();
    });
  });

  it('play button click should play audio and replay button should be enabled after audio stops', async () => {
    await setup(resultData);

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() => screen.getByTestId('audioElement').dispatchEvent(new window.Event('ended')));
    await waitFor(() => {
      expect(screen.getByRole('img', { name: 'Replay Icon' })).toBeInTheDocument();
    });

    userEvent.click(screen.getByRole('img', { name: 'Replay Icon' }));

    await waitFor(() => {
      expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument();
    });
  });

  it('should test the cancel button functionality', async () => {
    await setup(resultData);

    expect(screen.getByRole('button', { name: 'cancel' })).toBeDisabled();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    userEvent.type(screen.getByRole('textbox', { name: 'addText (hindi)' }), 'बपपप');

    expect(screen.getByRole('button', { name: 'cancel' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'cancel' }));

    expect(screen.getByRole('button', { name: 'cancel' })).toBeDisabled();

    userEvent.type(screen.getByRole('textbox', { name: 'addText (hindi)' }), 'abc');

    expect(screen.getByRole('button', { name: 'cancel' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'cancel' }));

    expect(screen.getByRole('button', { name: 'cancel' })).toBeDisabled();

    await waitFor(() => {
      expect(screen.getByRole('textbox', { name: 'addText (hindi)' })).toHaveValue('');
    });
  });

  it('should test the skip functionality', async () => {
    const url = '/skip';
    const successResponse = { message: 'Skipped successfully.', statusCode: 200 };

    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockResponseOnce(JSON.stringify(successResponse));

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          language: 'Hindi',
          sentenceId: 1248671,
          state_region: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'asr',
        }),
      });
    });
  });

  it('should test the submit button', async () => {
    const url = '/store';
    const successResponse = { success: true };

    await setup(resultData);

    fetchMock.doMockOnceIf(url).mockResponseOnce(JSON.stringify(successResponse));

    expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument();

    userEvent.click(screen.getByRole('img', { name: 'Pause Icon' }));

    expect(screen.getByRole('img', { name: 'Play Icon' })).toBeInTheDocument();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() => {
      screen.getByTestId('audioElement').dispatchEvent(new window.Event('ended'));
    });

    await waitFor(() => {
      expect(screen.getByRole('img', { name: 'Replay Icon' })).toBeInTheDocument();
    });

    userEvent.type(screen.getByRole('textbox', { name: 'addText (hindi)' }), 'बपपप');

    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'submit' })).toBeEnabled();
    });

    userEvent.click(screen.getByRole('button', { name: 'submit' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          userInput: 'बपपप',
          speakerDetails: '{"userName":"abc"}',
          language: 'Hindi',
          type: 'asr',
          sentenceId: 1248671,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          device: 'android 11',
          browser: 'Chrome 13',
        }),
      });
    });

    await waitFor(() => expect(screen.queryByRole('img', { name: 'check' })).toBeInTheDocument());

    await waitFor(() => expect(screen.queryByRole('img', { name: 'check' })).not.toBeInTheDocument());
  });

  it('should throw the error for last sentence', async () => {
    const url = '/skip';
    const errorResponse = new Error('Some error');
    await setup(resultData);

    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          language: 'Hindi',
          sentenceId: 1248671,
          state_region: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'asr',
        }),
      });
    });

    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });
  });

  it('should go to thank you page after 5 skip sentences', async () => {
    const url = '/skip';
    const successResponse = { message: 'Skipped successfully.', statusCode: 200 };

    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockResponseOnce(JSON.stringify(successResponse));
    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          language: 'Hindi',
          sentenceId: 1248671,
          state_region: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'asr',
        }),
      });
    });

    expect(screen.getByRole('button', { name: 'skip' })).toBeDisabled();
  });
});
Example #14
Source File: TtsValidate.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('TtsValidate', () => {
  const storeUrl = '/store';
  const skipUrl = '/skip';
  const acceptUrl = '/validate/1717503/accept';
  const rejectUrl = '/validate/1717503/reject';
  const successResponse = { success: true };
  const locationInfo = {
    country: 'India',
    regionName: 'National Capital Territory of Delhi',
  };

  const speakerDetails = {
    userName: 'abc',
    motherTongue: '',
    age: '',
    gender: '',
    language: 'Hindi',
    toLanguage: '',
  };

  const contributionsData = JSON.stringify({
    data: [
      {
        contribution_id: 1717503,
        dataset_row_id: 1248712,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-202131192011.wav',
        contribution: 'सोल को अगर आप नहीं देख सकते शीशा लगा करके आप जरूर देखिए',
        source_info: null,
      },
      {
        contribution_id: 1717502,
        dataset_row_id: 1248711,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-202121195940.wav',
        contribution: 'नहीं देख सकते शीशा लगा करके आप जरूर देखिए',
        source_info: null,
      },
      {
        contribution_id: 1717501,
        dataset_row_id: 1248710,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-202112711182.wav',
        contribution: 'आप जरूर देखिए',
        source_info: null,
      },
      {
        contribution_id: 1717497,
        dataset_row_id: 1248705,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-202083094241.wav',
        contribution: 'देखिए',
        source_info: null,
      },
      {
        contribution_id: 1717496,
        dataset_row_id: 1248704,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-20208293814.wav',
        contribution: 'देखिए',
        source_info: null,
      },
    ],
  });

  const setup = async () => {
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'Hindi');

    when(localStorage.getItem)
      .calledWith('locationInfo')
      .mockImplementation(() => JSON.stringify(locationInfo));

    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(() => JSON.stringify(speakerDetails));

    fetchMock
      .doMockOnceIf('/contributions/asr?from=Hindi&to=&username=abc')
      .mockResponseOnce(contributionsData);
    fetchMock.doMockIf(storeUrl).mockResponse(JSON.stringify(successResponse));
    fetchMock.doMockIf(skipUrl).mockResponse(JSON.stringify(successResponse));
    fetchMock.doMockIf(acceptUrl).mockResponse(JSON.stringify(successResponse));
    fetchMock.doMockIf(rejectUrl).mockResponse(JSON.stringify(successResponse));
    const renderResult = render(
      <SWRConfig value={{ provider: () => new Map() }}>
        <TtsValidate />
        <div id="report">
          <button>Stop Audio</button>
        </div>
      </SWRConfig>
    );

    await waitForElementToBeRemoved(() => screen.queryAllByTestId('Loader'));

    return renderResult;
  };

  it('needs change and correct button should be disabled initially', async () => {
    await setup();

    expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeDisabled();
  });

  it('play button and skip button should be enabled initially', async () => {
    await setup();

    expect(screen.getByRole('button', { name: 'Play Icon play' })).toBeEnabled();
    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();
  });

  it('should abort the audio when user clicks on report, test speaker, feedback button', async () => {
    await setup();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    userEvent.click(screen.getByRole('button', { name: /Stop Audio/ }));

    await waitFor(() => {
      expect(screen.getByRole('img', { name: 'Play Icon' })).toBeInTheDocument();
    });
  });

  it('play button click should play audio and pause button should be enabled', async () => {
    await setup();

    expect(screen.getByRole('img', { name: 'Play Icon' })).toBeInTheDocument();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument();
  });

  it('pause button click should pause audio and play button should be enabled', async () => {
    await setup();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument();

    userEvent.click(screen.getByRole('img', { name: 'Pause Icon' }));

    expect(screen.getByRole('img', { name: 'Play Icon' })).toBeInTheDocument();
  });

  it('should enable needs change and correct button when full audio is played', async () => {
    await setup();

    await waitFor(() => expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeDisabled());
    await waitFor(() => expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeDisabled());

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() => screen.getByTestId('audioElement').dispatchEvent(new window.Event('ended')));
    await waitFor(() => expect(screen.getByRole('img', { name: 'Replay Icon' })).toBeInTheDocument());
    await waitFor(() => expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeEnabled());
    await waitFor(() => expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeEnabled());
  });

  it('should replay full audio is played and replay clicked', async () => {
    await setup();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() => screen.getByTestId('audioElement').dispatchEvent(new window.Event('ended')));
    await waitFor(() => expect(screen.getByRole('img', { name: 'Replay Icon' })).toBeInTheDocument());
    userEvent.click(screen.getByRole('img', { name: 'Replay Icon' }));
    await waitFor(() => expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument());
  });

  it('should show edit text area when needs change button clicked', async () => {
    await setup();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() => screen.getByTestId('audioElement').dispatchEvent(new window.Event('ended')));
    await waitFor(() => expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeEnabled());
    userEvent.click(screen.getByRole('button', { name: 'Edit Icon needsChange' }));
    expect(screen.queryByRole('button', { name: 'Edit Icon needsChange' })).not.toBeInTheDocument();

    expect(screen.getByRole('button', { name: 'cancel' })).toBeEnabled();
    expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();

    expect(screen.getByRole('textbox', { name: 'originalText' })).toBeInTheDocument();
    expect(screen.getByRole('textbox', { name: 'yourEdit (hindi)' })).toBeInTheDocument();
    userEvent.click(screen.getByRole('button', { name: 'cancel' }));
    await waitFor(() => expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeEnabled());
  });

  it('should not enable submit for short edit', async () => {
    await setup();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() => screen.getByTestId('audioElement').dispatchEvent(new window.Event('ended')));
    expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeEnabled();
    userEvent.click(screen.getByRole('button', { name: 'Edit Icon needsChange' }));
    userEvent.clear(screen.getByRole('textbox', { name: 'yourEdit (hindi)' }));
    userEvent.type(screen.getByRole('textbox', { name: 'yourEdit (hindi)' }), 'बप');
    expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
  });

  it('skip should show next text for valdiating', async () => {
    await setup();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/validate/1717503/skip', {
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'asr',
        }),
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        mode: 'cors',
      });
    });
    expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Play Icon play' })).toBeEnabled();
    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();
    expect(screen.getByText('2/5')).toBeInTheDocument();
  });

  it('correct should show next text for validating', async () => {
    await setup();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() => screen.getByTestId('audioElement').dispatchEvent(new window.Event('ended')));
    await waitFor(() => expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeEnabled());
    userEvent.click(screen.getByRole('button', { name: 'Correct Icon correct' }));

    await waitFor(() =>
      expect(fetchMock).toBeCalledWith('/validate/1717503/accept', {
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'asr',
        }),
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        mode: 'cors',
      })
    );

    expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Play Icon play' })).toBeEnabled();
    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();
    expect(screen.getByText('2/5')).toBeInTheDocument();
  });

  it('should show the error popup when api throw the error and close modal on clicking button', async () => {
    const url = '/validate/1717503/accept';
    const errorResponse = new Error('Some error');
    await setup();
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);
    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));
    await waitFor(() => screen.getByTestId('audioElement').dispatchEvent(new window.Event('ended')));
    await waitFor(() => expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeEnabled());
    userEvent.click(screen.getByRole('button', { name: 'Correct Icon correct' }));
    await waitFor(() =>
      expect(fetchMock).toBeCalledWith(url, {
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'asr',
        }),
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        mode: 'cors',
      })
    );

    expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Play Icon play' })).toBeEnabled();
    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();
    expect(screen.getByText('2/5')).toBeInTheDocument();
    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(screen.queryByText('apiFailureError')).not.toBeInTheDocument();
    });
  });

  it('should call /store and /validate endpoint when a correction is done', async () => {
    await setup();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() => screen.getByTestId('audioElement').dispatchEvent(new window.Event('ended')));
    expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeEnabled();
    userEvent.click(screen.getByRole('button', { name: 'Edit Icon needsChange' }));
    expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    userEvent.clear(screen.getByRole('textbox', { name: 'yourEdit (hindi)' }));
    userEvent.type(screen.getByRole('textbox', { name: 'yourEdit (hindi)' }), 'बपपप');
    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'submit' })).toBeEnabled();
    });
    userEvent.click(screen.getByRole('button', { name: 'submit' }));
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(storeUrl, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          country: 'India',
          state: 'National Capital Territory of Delhi',
          language: 'Hindi',
          type: 'asr',
          sentenceId: 1248712,
          userInput: 'बपपप',
          speakerDetails: JSON.stringify({
            userName: 'abc',
          }),
        }),
      });
    });
    await waitFor(() => expect(screen.getByRole('img', { name: 'check' })).toBeInTheDocument());

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(rejectUrl, {
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          country: 'India',
          state: 'National Capital Territory of Delhi',
          userName: 'abc',
          type: 'asr',
        }),
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        mode: 'cors',
      });
    });
    await waitFor(() => expect(screen.queryByRole('img', { name: 'check' })).not.toBeInTheDocument());
  });

  it('should show no data text when fetch call gives no data', async () => {
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'Hindi');

    const speakerDetails = {
      userName: 'abc',
      motherTongue: '',
      age: '',
      gender: '',
      language: 'Hindi',
      toLanguage: '',
    };

    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(() => JSON.stringify(speakerDetails));

    fetchMock
      .doMockIf('/contributions/asr?from=Hindi&to=&username=abc')
      .mockResponse(JSON.stringify({ data: [] }));
    render(
      <SWRConfig value={{ provider: () => new Map() }}>
        <TtsValidate />
      </SWRConfig>
    );
    await waitForElementToBeRemoved(() => screen.queryAllByTestId('Loader'));
    await waitFor(() => {
      expect(screen.getByText('noDataMessage')).toBeInTheDocument();
    });
  });

  it('should throw the error for last sentence', async () => {
    await setup();
    const url = '/skip';
    const errorResponse = new Error('Some error');
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/validate/1717503/skip', {
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'asr',
        }),
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        mode: 'cors',
      });
    });

    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    // await waitFor(() => {
    //   expect(screen.queryByText('apiFailureError')).not.toBeInTheDocument();
    // });
  });

  it('should go to thank you page after 5 skip sentences', async () => {
    await setup();

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/validate/1717503/skip', {
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'asr',
        }),
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        mode: 'cors',
      });
    });
    expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Play Icon play' })).toBeEnabled();
    expect(screen.getByRole('button', { name: 'skip' })).toBeDisabled();
    expect(screen.getByText('5/5')).toBeInTheDocument();
  });

  it('should go to thank you page when user skip 4 and validate last sentence', async () => {
    await setup();

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/validate/1717503/skip', {
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'asr',
        }),
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        mode: 'cors',
      });
    });
    expect(screen.getByRole('button', { name: 'Edit Icon needsChange' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Play Icon play' })).toBeEnabled();
    expect(screen.getByRole('button', { name: 'skip' })).toBeDisabled();
    expect(screen.getByText('5/5')).toBeInTheDocument();
  });
});
Example #15
Source File: TyTargetProgress.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('TyTargetProgress', () => {
  const setup = async (
    initiative: 'tts' | 'asr' | 'translation' | 'ocr',
    initiativeMedia: 'asr' | 'ocr' | 'parallel' | 'text',
    source?: string,
    contributionLanguage?: string
  ) => {
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'Hindi');

    when(localStorage.getItem)
      .calledWith('translatedLanguage')
      .mockImplementation(() => 'English');

    fetchMock.doMockOnceIf('/aggregated-json/cumulativeDataByLanguage.json').mockResponseOnce(
      JSON.stringify([
        {
          language: 'Hindi',
          total_contribution_count: 45,
          total_contributions: 0.031,
          total_languages: 2,
          total_speakers: 11,
          total_validation_count: 8,
          total_validations: 0.002,
          type: 'asr',
        },
        {
          language: 'English',
          total_contribution_count: 45,
          total_contributions: 0.0,
          total_languages: 3,
          total_speakers: 11,
          total_validation_count: 9,
          total_validations: 0.0,
          type: 'ocr',
        },
        {
          language: 'Hindi-English',
          total_contribution_count: 45,
          total_contributions: 0.0,
          total_languages: 2,
          total_speakers: 10,
          total_validation_count: 8,
          total_validations: 0.0,
          type: 'parallel',
        },
        {
          language: 'English',
          total_contribution_count: 45,
          total_contributions: 6.3,
          total_languages: 2,
          total_speakers: 11,
          total_validation_count: 8,
          total_validations: 0.2,
          type: 'text',
        },
      ])
    );

    fetchMock.doMockOnceIf('/aggregated-json/initiativeGoalsByLanguage.json').mockResponseOnce(
      JSON.stringify([
        {
          language: 'Hindi-English',
          contribution_goal: 60000,
          type: 'parallel',
          validation_goal: 60000,
        },
        {
          language: 'English',
          contribution_goal: 60000,
          type: 'ocr',
          validation_goal: 60000,
        },
        {
          language: 'Hindi',
          contribution_goal: 60,
          type: 'asr',
          validation_goal: 60,
        },
        {
          language: 'Hindi',
          contribution_goal: 60,
          type: 'text',
        },
      ])
    );

    const renderResult = render(
      <TyTargetProgress
        initiative={initiative}
        initiativeType={initiativeMedia}
        source={source ?? ''}
        language={contributionLanguage ?? ''}
      />
    );
    await waitFor(() => {
      expect(localStorage.getItem).toBeCalled();
    });
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/aggregated-json/cumulativeDataByLanguage.json');
    });
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/aggregated-json/initiativeGoalsByLanguage.json');
    });
    return renderResult;
  };

  it('should render the component and matches it against stored snapshot', async () => {
    const { asFragment } = await setup('tts', 'asr', 'contribute', 'English');

    expect(asFragment()).toMatchSnapshot();
  });

  it('should render the result for tts initiative home page', async () => {
    await setup('tts', 'asr', 'contribute', 'Hindi');
    expect(screen.getByText('ttsProgressStatusWithLanguage')).toBeInTheDocument();
    expect(
      screen.getByText(content => {
        return content.includes('1 minutes1/60 hours1');
      })
    ).toBeInTheDocument();
  });

  it('should render the result for ocr initiative validate', async () => {
    await setup('ocr', 'ocr', 'validate', 'English');
    expect(screen.getByText('ocrProgressStatusWithLanguage')).toBeInTheDocument();
    expect(
      screen.getByText(content => {
        return content.includes('9/60000 images');
      })
    ).toBeInTheDocument();
  });

  it('should render the result for ocr initiative contribute', async () => {
    await setup('ocr', 'ocr', 'contribute', 'English');
    expect(screen.getByText('ocrProgressStatusWithLanguage')).toBeInTheDocument();
    expect(
      screen.getByText(content => {
        return content.includes('45/60000 images');
      })
    ).toBeInTheDocument();
  });

  it('should render the result for ocr initiative validate without language', async () => {
    await setup('ocr', 'ocr', 'validate');
    expect(screen.getByText('ocrProgressStatusWithLanguage')).toBeInTheDocument();
    expect(
      screen.getByText(content => {
        return content.includes('0/60000 images');
      })
    ).toBeInTheDocument();
  });

  it('should render the result for translation initiative contribute', async () => {
    await setup('translation', 'parallel', undefined, 'English');

    expect(screen.getByText('translationProgressStatusWithLanguage')).toBeInTheDocument();
    expect(
      screen.getByText(content => {
        return content.includes('0/1 sentences');
      })
    ).toBeInTheDocument();
  });

  it('should print goal as 1 if goal is undefined', async () => {
    await setup('asr', 'text', 'validate', 'Hindi');

    expect(
      screen.getByText(content => {
        return content.includes('/1 hours');
      })
    ).toBeInTheDocument();
  });
});
Example #16
Source File: UserOptions.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('UserOptions', () => {
  const setup = () => {
    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(() => null);

    return render(<UserOptions />);
  };
  const setupWithSpeakerDetails = (data = {}) => {
    const speakerDetails = {
      gender: 'male',
      age: '',
      motherTongue: 'Hindi',
      userName: 'abcd',
      language: 'Hindi',
      toLanguage: '',
      ...data,
    };
    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(() => JSON.stringify(speakerDetails));

    return render(<UserOptions />);
  };

  verifyAxeTest(() => setup());
  verifyAxeTest(() => setupWithSpeakerDetails());

  it('should not render the component when speaker details are not present', () => {
    const { asFragment } = setup();

    expect(asFragment()).toMatchSnapshot();
  });

  it('should render the component when speaker details are present', () => {
    const { asFragment } = setupWithSpeakerDetails();

    expect(asFragment()).toMatchSnapshot();
  });

  it('should render the component when speaker details are present but username is not present', () => {
    const { asFragment } = setupWithSpeakerDetails({
      userName: '',
    });

    expect(asFragment()).toMatchSnapshot();
  });

  it('should hide ChangeUserModal initially', () => {
    setupWithSpeakerDetails();

    expect(screen.queryByTestId('ChangeUserModal')).not.toBeInTheDocument();
  });

  it('should show ChangeUserModal when change user option is clicked', async () => {
    setupWithSpeakerDetails();

    userEvent.click(screen.getByRole('button', { name: 'Language Icon abcd' }));

    await waitFor(() => expect(screen.getByRole('button', { name: 'changeUser' })).toBeInTheDocument());

    userEvent.click(screen.getByRole('button', { name: 'changeUser' }));

    expect(screen.getByTestId('ChangeUserModal')).toBeInTheDocument();

    userEvent.click(screen.getByRole('button', { name: 'Close' }));

    await waitForElementToBeRemoved(() => screen.queryByTestId('ChangeUserModal'));

    expect(screen.queryByTestId('ChangeUserModal')).not.toBeInTheDocument();
  });

  it('should navigate to my badges page on "my badges" link click', async () => {
    setupWithSpeakerDetails();

    userEvent.click(screen.getByRole('button', { name: 'Language Icon abcd' }));

    await waitFor(() => expect(screen.getByRole('button', { name: 'changeUser' })).toBeInTheDocument());

    expect(router.pathname).toBe('');

    userEvent.click(screen.getByRole('link', { name: 'myBadges' }));

    expect(router.pathname).toBe('/my-badges');
  });
});
Example #17
Source File: TranslationDashboard.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('TranslationDashboard', () => {
  global.document.getElementById = jest.fn().mockImplementation(
    x =>
      x === 'float' && {
        style: {
          width: '50%',
        },
      }
  );

  const fromLanguageElement = () => screen.getByRole('combobox', { name: 'Select From Language' });
  const toLanguageElement = () => screen.getByRole('combobox', { name: 'Select To Language' });

  const setup = async () => {
    fetchMock.doMockIf('/aggregated-json/cumulativeDataByLanguage.json').mockResponse(
      JSON.stringify([
        {
          language: 'English-Hindi',
          total_contribution_count: 36,
          total_contributions: 0.057,
          total_speakers: 9,
          total_validation_count: 2,
          total_validations: 0.001,
          type: 'parallel',
        },
      ])
    );
    const renderResult = render(
      <SWRConfig value={{ provider: () => new Map() }}>
        <TranslationDashboard />
      </SWRConfig>
    );
    await screen.findByText('ContributionStats');
    return renderResult;
  };

  it('should contain language selector', async () => {
    await setup();
    expect(fromLanguageElement()).toBeInTheDocument();
    expect(toLanguageElement()).toBeInTheDocument();
    expect(toLanguageElement()).toBeDisabled();
  });

  it('changing language in language pair selector should update stats', async () => {
    await setup();
    userEvent.selectOptions(fromLanguageElement(), 'English');
    expect(toLanguageElement()).toBeEnabled();
    userEvent.selectOptions(toLanguageElement(), 'Hindi');
    await waitForElementToBeRemoved(() => screen.queryAllByTestId('Loader'));
    expect(fetchMock).toBeCalledWith('/aggregated-json/cumulativeDataByLanguage.json');
    expect(screen.queryByText('languages')).not.toBeInTheDocument();
  });

  it('changing from language back to all should show all language stats', async () => {
    await setup();
    userEvent.selectOptions(fromLanguageElement(), 'English');
    expect(toLanguageElement()).toBeEnabled();
    userEvent.selectOptions(fromLanguageElement(), 'all');
    expect(fromLanguageElement()).toHaveValue('all');
    expect(toLanguageElement()).toHaveValue('all');
  });

  it('should show default languages when all languages selected in to language dropdown', async () => {
    await setup();
    userEvent.selectOptions(fromLanguageElement(), 'English');
    userEvent.selectOptions(toLanguageElement(), 'Hindi');
    userEvent.selectOptions(toLanguageElement(), 'all');
    await waitFor(() => expect(fromLanguageElement()).toHaveValue('all'));
    await waitFor(() => expect(toLanguageElement()).toHaveValue('all'));
  });

  it('changing language from language pair selector should display nodata message when data not available', async () => {
    await setup();
    userEvent.selectOptions(fromLanguageElement(), 'English');
    userEvent.selectOptions(toLanguageElement(), 'Hindi');
    await waitForElementToBeRemoved(() => screen.queryAllByTestId('Loader'));
    userEvent.selectOptions(toLanguageElement(), 'Bengali');
    await waitFor(() => expect(fetchMock).toBeCalledWith('/aggregated-json/cumulativeDataByLanguage.json'));
    await waitFor(() => expect(screen.getByText('noDataMessageDashboard')).toBeInTheDocument());
    await waitFor(() => expect(screen.queryByText('noDataMessageDashboard')).not.toBeInTheDocument());
    expect(screen.queryByText('languages')).not.toBeInTheDocument();
  });

  it('changing to language where data not available and clicking contribute now should display change user modal for new user', async () => {
    await setup();
    userEvent.selectOptions(fromLanguageElement(), 'English');
    userEvent.selectOptions(toLanguageElement(), 'Bengali');
    await waitFor(() => {
      expect(screen.getByText('noDataMessageDashboard')).toBeInTheDocument();
    });
    userEvent.click(screen.getByRole('button', { name: 'contributeNow' }));
    await waitFor(() => expect(screen.getByTestId('ChangeUserForm')).toBeInTheDocument());

    userEvent.click(screen.getByRole('button', { name: 'Close' }));

    await waitForElementToBeRemoved(() => screen.queryByTestId('ChangeUserModal'));
  });

  it('changing to language where data not available and clicking contribute now should redirect for existing user', async () => {
    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(
        () => '{"userName":"abc","motherTongue":"","age":"","gender":"","language":"English","toLanguage":""}'
      );
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'English');
    when(localStorage.getItem)
      .calledWith('translatedLanguage')
      .mockImplementation(() => 'Hindi');
    await setup();
    await waitFor(() => {
      expect(localStorage.getItem).toBeCalled();
    });
    userEvent.selectOptions(fromLanguageElement(), 'English');
    userEvent.selectOptions(toLanguageElement(), 'Bengali');
    await waitFor(() => {
      expect(screen.getByText('noDataMessageDashboard')).toBeInTheDocument();
    });
    userEvent.click(screen.getByRole('button', { name: 'contributeNow' }));
    await waitFor(() => expect(screen.queryByTestId('ChangeUserModal')).not.toBeInTheDocument());
    expect(localStorage.setItem).toBeCalledWith('contributionLanguage', 'English');
    expect(localStorage.setItem).toBeCalledWith('translatedLanguage', 'Bengali');
  });
});
Example #18
Source File: router.test.ts    From backstage with Apache License 2.0 4 votes vote down vote up
describe('router', () => {
  let app: express.Express;
  let apis: ClusterApi[];
  let devKafkaApi: jest.Mocked<KafkaApi>;
  let prodKafkaApi: jest.Mocked<KafkaApi>;

  beforeAll(async () => {
    devKafkaApi = {
      fetchTopicOffsets: jest.fn(),
      fetchGroupOffsets: jest.fn(),
    };

    prodKafkaApi = {
      fetchTopicOffsets: jest.fn(),
      fetchGroupOffsets: jest.fn(),
    };

    apis = [
      { name: 'dev', api: devKafkaApi },
      { name: 'prod', api: prodKafkaApi },
    ];

    const router = makeRouter(getVoidLogger(), apis);
    app = express().use(router);
  });

  beforeEach(() => {
    jest.resetAllMocks();
  });

  describe('get /consumers/clusterId/:consumerId/offsets', () => {
    it('returns topic and group offsets', async () => {
      const topic1Offsets = [
        { id: 1, offset: '500' },
        { id: 2, offset: '1000' },
      ];
      const topic2Offsets = [{ id: 1, offset: '456' }];

      const groupOffsets = [
        {
          topic: 'topic1',
          partitions: [
            { id: 1, offset: '100' },
            { id: 2, offset: '213' },
          ],
        },
        {
          topic: 'topic2',
          partitions: [{ id: 1, offset: '456' }],
        },
      ];
      when(prodKafkaApi.fetchTopicOffsets)
        .calledWith('topic1')
        .mockResolvedValue(topic1Offsets);
      when(prodKafkaApi.fetchTopicOffsets)
        .calledWith('topic2')
        .mockResolvedValue(topic2Offsets);
      when(prodKafkaApi.fetchGroupOffsets)
        .calledWith('hey')
        .mockResolvedValue(groupOffsets);

      const response = await request(app).get('/consumers/prod/hey/offsets');

      expect(response.status).toEqual(200);
      expect(response.body.consumerId).toEqual('hey');
      // Note the Set comparison here since there's no guarantee on the order of the elements in the list.
      expect(new Set(response.body.offsets)).toStrictEqual(
        new Set([
          {
            topic: 'topic1',
            partitionId: 1,
            groupOffset: '100',
            topicOffset: '500',
          },
          {
            topic: 'topic1',
            partitionId: 2,
            groupOffset: '213',
            topicOffset: '1000',
          },
          {
            topic: 'topic2',
            partitionId: 1,
            groupOffset: '456',
            topicOffset: '456',
          },
        ]),
      );
    });

    it('handles unknown cluster errors correctly', async () => {
      const response = await request(app.use(errorHandler())).get(
        '/consumers/unknown/hey/offsets',
      );
      expect(response.status).toEqual(404);
      expect(response.body).toMatchObject({
        error: {
          message:
            'Found no configured cluster "unknown", candidates are "dev", "prod"',
        },
      });
    });

    it('handles internal error correctly', async () => {
      prodKafkaApi.fetchGroupOffsets.mockRejectedValue(Error('oh no'));

      const response = await request(app).get('/consumers/prod/hey/offsets');

      expect(response.status).toEqual(500);
    });

    it('uses correct kafka cluster', async () => {
      const topic1ProdOffsets = [{ id: 1, offset: '500' }];
      const topic1DevOffsets = [{ id: 1, offset: '1234' }];
      const groupProdOffsets = [
        {
          topic: 'topic1',
          partitions: [{ id: 1, offset: '100' }],
        },
      ];
      const groupDevOffsets = [
        {
          topic: 'topic1',
          partitions: [{ id: 1, offset: '567' }],
        },
      ];
      when(prodKafkaApi.fetchTopicOffsets)
        .calledWith('topic1')
        .mockResolvedValue(topic1ProdOffsets);
      when(prodKafkaApi.fetchGroupOffsets)
        .calledWith('hey')
        .mockResolvedValue(groupProdOffsets);
      when(devKafkaApi.fetchTopicOffsets)
        .calledWith('topic1')
        .mockResolvedValue(topic1DevOffsets);
      when(devKafkaApi.fetchGroupOffsets)
        .calledWith('hey')
        .mockResolvedValue(groupDevOffsets);

      const prodResponse = await request(app).get(
        '/consumers/prod/hey/offsets',
      );
      const devResponse = await request(app).get('/consumers/dev/hey/offsets');

      expect(prodResponse.status).toEqual(200);
      expect(prodResponse.body.consumerId).toEqual('hey');
      expect(new Set(prodResponse.body.offsets)).toStrictEqual(
        new Set([
          {
            topic: 'topic1',
            partitionId: 1,
            groupOffset: '100',
            topicOffset: '500',
          },
        ]),
      );
      expect(devResponse.status).toEqual(200);
      expect(devResponse.body.consumerId).toEqual('hey');
      expect(new Set(devResponse.body.offsets)).toStrictEqual(
        new Set([
          {
            topic: 'topic1',
            partitionId: 1,
            groupOffset: '567',
            topicOffset: '1234',
          },
        ]),
      );
    });
  });
});
Example #19
Source File: github.test.ts    From backstage with Apache License 2.0 4 votes vote down vote up
describe('publish:github', () => {
  const config = new ConfigReader({
    integrations: {
      github: [
        { host: 'github.com', token: 'tokenlols' },
        { host: 'ghe.github.com' },
      ],
    },
  });

  const integrations = ScmIntegrations.fromConfig(config);
  let githubCredentialsProvider: GithubCredentialsProvider;
  let action: TemplateAction<any>;

  const mockContext = {
    input: {
      repoUrl: 'github.com?repo=repo&owner=owner',
      description: 'description',
      repoVisibility: 'private' as const,
      access: 'owner/blam',
    },
    workspacePath: 'lol',
    logger: getVoidLogger(),
    logStream: new PassThrough(),
    output: jest.fn(),
    createTemporaryDirectory: jest.fn(),
  };

  beforeEach(() => {
    jest.resetAllMocks();
    githubCredentialsProvider =
      DefaultGithubCredentialsProvider.fromIntegrations(integrations);
    action = createPublishGithubAction({
      integrations,
      config,
      githubCredentialsProvider,
    });
  });

  it('should call the githubApis with the correct values for createInOrg', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'Organization' },
    });

    mockOctokit.rest.repos.createInOrg.mockResolvedValue({ data: {} });

    await action.handler(mockContext);
    expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({
      description: 'description',
      name: 'repo',
      org: 'owner',
      private: true,
      delete_branch_on_merge: false,
      allow_squash_merge: true,
      allow_merge_commit: true,
      allow_rebase_merge: true,
      visibility: 'private',
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        repoVisibility: 'public',
      },
    });
    expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({
      description: 'description',
      name: 'repo',
      org: 'owner',
      private: false,
      delete_branch_on_merge: false,
      allow_squash_merge: true,
      allow_merge_commit: true,
      allow_rebase_merge: true,
      visibility: 'public',
    });
  });

  it('should call the githubApis with the correct values for createForAuthenticatedUser', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {},
    });

    await action.handler(mockContext);
    expect(
      mockOctokit.rest.repos.createForAuthenticatedUser,
    ).toHaveBeenCalledWith({
      description: 'description',
      name: 'repo',
      private: true,
      delete_branch_on_merge: false,
      allow_squash_merge: true,
      allow_merge_commit: true,
      allow_rebase_merge: true,
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        repoVisibility: 'public',
      },
    });
    expect(
      mockOctokit.rest.repos.createForAuthenticatedUser,
    ).toHaveBeenCalledWith({
      description: 'description',
      name: 'repo',
      private: false,
      delete_branch_on_merge: false,
      allow_squash_merge: true,
      allow_merge_commit: true,
      allow_rebase_merge: true,
    });
  });

  it('should call initRepoAndPush with the correct values', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    await action.handler(mockContext);

    expect(initRepoAndPush).toHaveBeenCalledWith({
      dir: mockContext.workspacePath,
      remoteUrl: 'https://github.com/clone/url.git',
      defaultBranch: 'master',
      auth: { username: 'x-access-token', password: 'tokenlols' },
      logger: mockContext.logger,
      commitMessage: 'initial commit',
      gitAuthorInfo: {},
    });
  });

  it('should call initRepoAndPush with the correct defaultBranch main', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        defaultBranch: 'main',
      },
    });

    expect(initRepoAndPush).toHaveBeenCalledWith({
      dir: mockContext.workspacePath,
      remoteUrl: 'https://github.com/clone/url.git',
      defaultBranch: 'main',
      auth: { username: 'x-access-token', password: 'tokenlols' },
      logger: mockContext.logger,
      commitMessage: 'initial commit',
      gitAuthorInfo: {},
    });
  });

  it('should call initRepoAndPush with the configured defaultAuthor', async () => {
    const customAuthorConfig = new ConfigReader({
      integrations: {
        github: [
          { host: 'github.com', token: 'tokenlols' },
          { host: 'ghe.github.com' },
        ],
      },
      scaffolder: {
        defaultAuthor: {
          name: 'Test',
          email: '[email protected]',
        },
      },
    });

    const customAuthorIntegrations =
      ScmIntegrations.fromConfig(customAuthorConfig);
    const customAuthorAction = createPublishGithubAction({
      integrations: customAuthorIntegrations,
      config: customAuthorConfig,
      githubCredentialsProvider,
    });

    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    await customAuthorAction.handler(mockContext);

    expect(initRepoAndPush).toHaveBeenCalledWith({
      dir: mockContext.workspacePath,
      remoteUrl: 'https://github.com/clone/url.git',
      defaultBranch: 'master',
      auth: { username: 'x-access-token', password: 'tokenlols' },
      logger: mockContext.logger,
      commitMessage: 'initial commit',
      gitAuthorInfo: { name: 'Test', email: '[email protected]' },
    });
  });

  it('should call initRepoAndPush with the configured defaultCommitMessage', async () => {
    const customAuthorConfig = new ConfigReader({
      integrations: {
        github: [
          { host: 'github.com', token: 'tokenlols' },
          { host: 'ghe.github.com' },
        ],
      },
      scaffolder: {
        defaultCommitMessage: 'Test commit message',
      },
    });

    const customAuthorIntegrations =
      ScmIntegrations.fromConfig(customAuthorConfig);
    const customAuthorAction = createPublishGithubAction({
      integrations: customAuthorIntegrations,
      config: customAuthorConfig,
      githubCredentialsProvider,
    });

    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    await customAuthorAction.handler(mockContext);

    expect(initRepoAndPush).toHaveBeenCalledWith({
      dir: mockContext.workspacePath,
      remoteUrl: 'https://github.com/clone/url.git',
      defaultBranch: 'master',
      auth: { username: 'x-access-token', password: 'tokenlols' },
      logger: mockContext.logger,
      commitMessage: 'initial commit',
      gitAuthorInfo: { email: undefined, name: undefined },
    });
  });

  it('should add access for the team when it starts with the owner', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    await action.handler(mockContext);

    expect(
      mockOctokit.rest.teams.addOrUpdateRepoPermissionsInOrg,
    ).toHaveBeenCalledWith({
      org: 'owner',
      team_slug: 'blam',
      owner: 'owner',
      repo: 'repo',
      permission: 'admin',
    });
  });

  it('should add outside collaborators when provided', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        access: 'outsidecollaborator',
      },
    });

    expect(mockOctokit.rest.repos.addCollaborator).toHaveBeenCalledWith({
      username: 'outsidecollaborator',
      owner: 'owner',
      repo: 'repo',
      permission: 'admin',
    });
  });

  it('should add multiple collaborators when provided', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        collaborators: [
          {
            access: 'pull',
            user: 'robot-1',
          },
          {
            access: 'push',
            team: 'robot-2',
          },
        ],
      },
    });

    const commonProperties = {
      owner: 'owner',
      repo: 'repo',
    };

    expect(mockOctokit.rest.repos.addCollaborator).toHaveBeenCalledWith({
      ...commonProperties,
      username: 'robot-1',
      permission: 'pull',
    });

    expect(
      mockOctokit.rest.teams.addOrUpdateRepoPermissionsInOrg,
    ).toHaveBeenCalledWith({
      ...commonProperties,
      org: 'owner',
      team_slug: 'robot-2',
      permission: 'push',
    });
  });

  it('should ignore failures when adding multiple collaborators', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    when(mockOctokit.rest.teams.addOrUpdateRepoPermissionsInOrg)
      .calledWith({
        org: 'owner',
        owner: 'owner',
        repo: 'repo',
        team_slug: 'robot-1',
        permission: 'pull',
      })
      .mockRejectedValueOnce(new Error('Something bad happened') as never);

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        collaborators: [
          {
            access: 'pull',
            team: 'robot-1',
          },
          {
            access: 'push',
            team: 'robot-2',
          },
        ],
      },
    });

    expect(
      mockOctokit.rest.teams.addOrUpdateRepoPermissionsInOrg.mock.calls[2],
    ).toEqual([
      {
        org: 'owner',
        owner: 'owner',
        repo: 'repo',
        team_slug: 'robot-2',
        permission: 'push',
      },
    ]);
  });

  it('should add topics when provided', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    mockOctokit.rest.repos.replaceAllTopics.mockResolvedValue({
      data: {
        names: ['node.js'],
      },
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        topics: ['node.js'],
      },
    });

    expect(mockOctokit.rest.repos.replaceAllTopics).toHaveBeenCalledWith({
      owner: 'owner',
      repo: 'repo',
      names: ['node.js'],
    });
  });

  it('should lowercase topics when provided', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    mockOctokit.rest.repos.replaceAllTopics.mockResolvedValue({
      data: {
        names: ['backstage'],
      },
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        topics: ['BACKSTAGE'],
      },
    });

    expect(mockOctokit.rest.repos.replaceAllTopics).toHaveBeenCalledWith({
      owner: 'owner',
      repo: 'repo',
      names: ['backstage'],
    });
  });

  it('should call output with the remoteUrl and the repoContentsUrl', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    await action.handler(mockContext);

    expect(mockContext.output).toHaveBeenCalledWith(
      'remoteUrl',
      'https://github.com/clone/url.git',
    );
    expect(mockContext.output).toHaveBeenCalledWith(
      'repoContentsUrl',
      'https://github.com/html/url/blob/master',
    );
  });

  it('should use main as default branch', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        clone_url: 'https://github.com/clone/url.git',
        html_url: 'https://github.com/html/url',
      },
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        defaultBranch: 'main',
      },
    });

    expect(mockContext.output).toHaveBeenCalledWith(
      'remoteUrl',
      'https://github.com/clone/url.git',
    );
    expect(mockContext.output).toHaveBeenCalledWith(
      'repoContentsUrl',
      'https://github.com/html/url/blob/main',
    );
  });

  it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requireCodeOwnerReviews', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        name: 'repository',
      },
    });

    await action.handler(mockContext);

    expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({
      owner: 'owner',
      client: mockOctokit,
      repoName: 'repository',
      logger: mockContext.logger,
      defaultBranch: 'master',
      requireCodeOwnerReviews: false,
      requiredStatusCheckContexts: [],
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        requireCodeOwnerReviews: true,
      },
    });

    expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({
      owner: 'owner',
      client: mockOctokit,
      repoName: 'repository',
      logger: mockContext.logger,
      defaultBranch: 'master',
      requireCodeOwnerReviews: true,
      requiredStatusCheckContexts: [],
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        requireCodeOwnerReviews: false,
      },
    });

    expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({
      owner: 'owner',
      client: mockOctokit,
      repoName: 'repository',
      logger: mockContext.logger,
      defaultBranch: 'master',
      requireCodeOwnerReviews: false,
      requiredStatusCheckContexts: [],
    });
  });

  it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requiredStatusCheckContexts', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        name: 'repository',
      },
    });

    await action.handler(mockContext);

    expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({
      owner: 'owner',
      client: mockOctokit,
      repoName: 'repository',
      logger: mockContext.logger,
      defaultBranch: 'master',
      requireCodeOwnerReviews: false,
      requiredStatusCheckContexts: [],
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        requiredStatusCheckContexts: ['statusCheck'],
      },
    });

    expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({
      owner: 'owner',
      client: mockOctokit,
      repoName: 'repository',
      logger: mockContext.logger,
      defaultBranch: 'master',
      requireCodeOwnerReviews: false,
      requiredStatusCheckContexts: ['statusCheck'],
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        requiredStatusCheckContexts: [],
      },
    });

    expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({
      owner: 'owner',
      client: mockOctokit,
      repoName: 'repository',
      logger: mockContext.logger,
      defaultBranch: 'master',
      requireCodeOwnerReviews: false,
      requiredStatusCheckContexts: [],
    });
  });

  it('should not call enableBranchProtectionOnDefaultRepoBranch with protectDefaultBranch disabled', async () => {
    mockOctokit.rest.users.getByUsername.mockResolvedValue({
      data: { type: 'User' },
    });

    mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({
      data: {
        name: 'repository',
      },
    });

    await action.handler({
      ...mockContext,
      input: {
        ...mockContext.input,
        protectDefaultBranch: false,
      },
    });

    expect(enableBranchProtectionOnDefaultRepoBranch).not.toHaveBeenCalled();
  });
});
Example #20
Source File: ExposureNotificationService.spec.ts    From mobile with Apache License 2.0 4 votes vote down vote up
describe('ExposureNotificationService', () => {
  let service: ExposureNotificationService;

  const OriginalDate = global.Date;
  const dateSpy = jest.spyOn(global, 'Date');
  const today = new OriginalDate('2020-05-18T04:10:00+0000');

  const testUpdateExposure = async (currentStatus: ExposureStatus, summaries: ExposureSummary[]) => {
    service.exposureStatus.append(currentStatus);
    bridge.detectExposure.mockResolvedValueOnce(summaries);
    await service.updateExposureStatus();
    return service.exposureStatus.get();
  };

  beforeEach(() => {
    service = new ExposureNotificationService(server, i18n, storage, secureStorage, bridge);
    Platform.OS = 'ios';
    service.systemStatus.set(SystemStatus.Active);
    when(storage.getItem)
      .calledWith(Key.OnboardedDatetime)
      .mockResolvedValue(today.getTime());

    dateSpy.mockImplementation((...args: any[]) => (args.length > 0 ? new OriginalDate(...args) : today));
  });

  afterEach(() => {
    jest.clearAllMocks();
    resetAllWhenMocks();
    dateSpy.mockReset();
  });

  it.each(['ios', 'android'])('filters most recent over minutes threshold on %p', async os => {
    Platform.OS = os;
    const today = new OriginalDate('2020-09-22T00:00:00.000Z');
    const notExposedSummary = getSummary({
      today,
      hasMatchedKey: true,
      daysSinceLastExposure: 2,
      attenuationDurations: [5, 3, 0],
      os,
    });
    const exposedSummary1 = getSummary({
      today,
      hasMatchedKey: true,
      daysSinceLastExposure: 7,
      attenuationDurations: [17, 0, 0],
      os,
    });
    const exposedSummary2 = getSummary({
      today,
      hasMatchedKey: true,
      daysSinceLastExposure: 5,
      attenuationDurations: [0, 20, 0],
      os,
    });
    const summaries = [notExposedSummary, exposedSummary1, exposedSummary2];

    const result = service.findSummariesContainingExposures(15, summaries);
    expect(result).toHaveLength(2);
    expect(result[0]).toStrictEqual(exposedSummary2);
  });

  it.each([
    [[20, 0, 0], 'ios', ExposureStatusType.Exposed],
    [[30, 0, 0], 'ios', ExposureStatusType.Exposed],
    [[10, 0, 0], 'ios', ExposureStatusType.Monitoring],
    [[0, 10, 0], 'ios', ExposureStatusType.Monitoring],
    [[0, 10, 30], 'ios', ExposureStatusType.Monitoring],
    [[20, 0, 0], 'android', ExposureStatusType.Exposed],
    [[30, 0, 0], 'android', ExposureStatusType.Exposed],
    [[10, 0, 0], 'android', ExposureStatusType.Monitoring],
    [[0, 10, 0], 'android', ExposureStatusType.Monitoring],
    [[0, 10, 30], 'android', ExposureStatusType.Monitoring],
  ])(
    'given attenuationDurations = %p, os = %p, returns status %p',
    async (argAttenuationDurations, os, expectedStatus) => {
      Platform.OS = os;
      const today = new OriginalDate('2020-05-18T04:10:00+0000');

      const currentStatus: ExposureStatus = {
        type: ExposureStatusType.Monitoring,
      };

      const exposedSummary = getSummary({
        today,
        hasMatchedKey: true,
        daysSinceLastExposure: 7,
        attenuationDurations: argAttenuationDurations,
        os,
      });

      const newStatus = await testUpdateExposure(currentStatus, [exposedSummary]);

      expect(newStatus).toStrictEqual(expect.objectContaining({type: expectedStatus}));
    },
  );

  it.each([
    [1, 10, 'ios', ExposureStatusType.Exposed],
    [10, 10, 'ios', ExposureStatusType.Exposed],
    [20, 10, 'ios', ExposureStatusType.Exposed],
    [1, 20, 'ios', ExposureStatusType.Exposed],
    [10, 20, 'ios', ExposureStatusType.Exposed],
    [20, 20, 'ios', ExposureStatusType.Exposed],
    [1, 10, 'android', ExposureStatusType.Exposed],
    [10, 10, 'android', ExposureStatusType.Exposed],
    [20, 10, 'android', ExposureStatusType.Exposed],
    [1, 20, 'android', ExposureStatusType.Exposed],
    [10, 20, 'android', ExposureStatusType.Exposed],
    [20, 20, 'android', ExposureStatusType.Exposed],
  ])(
    'given daysSinceLastExposure = %p, immediateMinutes = %p, os = %p, returns status %p',
    async (argDaysSinceLastExposure, immediateMinutes, os, expectedStatus) => {
      // houdini test: if a user was exposed 7 days ago
      // and then they get a new summary with a matched key
      // but not enough time to trigger an exposure,
      // they stay exposed, no matter if the new match is
      // before or after the old match
      Platform.OS = os;
      const today = new OriginalDate('2020-05-18T04:10:00+0000');

      const currentSummary = getSummary({
        today,
        hasMatchedKey: true,
        daysSinceLastExposure: 7,
        attenuationDurations: [20, 0, 0],
        os,
      });

      const currentStatus: ExposureStatus = {
        type: ExposureStatusType.Exposed,
        summary: currentSummary,
      };

      const nextSummary = getSummary({
        today,
        hasMatchedKey: true,
        daysSinceLastExposure: argDaysSinceLastExposure,
        attenuationDurations: [immediateMinutes, 0, 0],
        os,
      });

      const newStatus = await testUpdateExposure(currentStatus, [nextSummary]);

      expect(newStatus).toStrictEqual(expect.objectContaining({type: expectedStatus}));
    },
  );

  it('filters out summaries with 0 matched keys', async () => {
    const today = new OriginalDate('2020-05-18T04:10:00+0000');

    const summaryConfig = {
      today,
      daysSinceLastExposure: 7,
      attenuationDurations: [20, 0, 0],
      os: 'ios',
    };

    const hasMatch = await service.findSummariesContainingExposures(15, [
      getSummary({
        hasMatchedKey: true,
        ...summaryConfig,
      }),
    ]);

    expect(hasMatch).toHaveLength(1);

    const noMatch = await service.findSummariesContainingExposures(15, [
      getSummary({
        hasMatchedKey: false,
        ...summaryConfig,
      }),
    ]);

    expect(noMatch).toHaveLength(0);
  });

  it('backfills keys when last timestamp not available', async () => {
    const today = new OriginalDate('2020-05-18T04:10:00+0000');
    dateSpy.mockImplementation((args: any) => {
      if (args === undefined) return new OriginalDate('2020-05-19T11:10:00+0000');
      return new OriginalDate(args);
    });

    await service.updateExposureStatus();
    expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(2);
  });

  it('ignores exposed summaries if they are not more recent than ignored summary', async () => {
    const summary1 = getSummary({
      hasMatchedKey: true,
      today,
      daysSinceLastExposure: 7,
      attenuationDurations: [20, 0, 0],
      os: 'ios',
    });

    const summary2 = getSummary({
      hasMatchedKey: true,
      today,
      daysSinceLastExposure: 7,
      attenuationDurations: [20, 0, 0],
      os: 'ios',
    });

    const summary3 = getSummary({
      hasMatchedKey: true,
      today,
      daysSinceLastExposure: 8,
      attenuationDurations: [22, 0, 0],
      os: 'ios',
    });

    const summary4 = getSummary({
      hasMatchedKey: true,
      today,
      daysSinceLastExposure: 6,
      attenuationDurations: [22, 0, 0],
      os: 'ios',
    });

    const ignoredSummaries = [summary1];

    service.exposureStatus.append({ignoredSummaries});

    expect(service.isIgnoredSummary(summary2)).toStrictEqual(true);
    expect(service.isIgnoredSummary(summary3)).toStrictEqual(true);
    expect(service.isIgnoredSummary(summary4)).toStrictEqual(false);
  });

  it('backfills the right amount of keys for current day', async () => {
    dateSpy.mockImplementation((args: any) => {
      if (args === undefined) return new OriginalDate('2020-05-19T11:10:00+0000');
      return new OriginalDate(args);
    });

    service.exposureStatus.append({
      lastChecked: {
        timestamp: new OriginalDate('2020-05-19T06:10:00+0000').getTime(),
        period: periodSinceEpoch(new OriginalDate('2020-05-19T06:10:00+0000'), HOURS_PER_PERIOD),
      },
    });

    await service.updateExposureStatus();

    expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(1);

    server.retrieveDiagnosisKeys.mockClear();

    service.exposureStatus.append({
      lastChecked: {
        timestamp: new OriginalDate('2020-05-18T05:10:00+0000').getTime(),
        period: periodSinceEpoch(new OriginalDate('2020-05-18T05:10:00+0000'), HOURS_PER_PERIOD),
      },
    });
    await service.updateExposureStatus();
    expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(2);

    server.retrieveDiagnosisKeys.mockClear();

    service.exposureStatus.append({
      lastChecked: {
        timestamp: new OriginalDate('2020-05-17T23:10:00+0000').getTime(),
        period: periodSinceEpoch(new OriginalDate('2020-05-17T23:10:00+0000'), HOURS_PER_PERIOD),
      },
    });
    await service.updateExposureStatus();
    expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(3);
  });

  it('serializes status update', async () => {
    const updatePromise = service.updateExposureStatus();
    const anotherUpdatePromise = service.updateExposureStatus();
    await Promise.all([updatePromise, anotherUpdatePromise]);
    expect(server.getExposureConfiguration).toHaveBeenCalledTimes(1);
  });

  // eslint-disable-next-line jest/no-disabled-tests
  it.skip('stores last update timestamp', async () => {
    const currentDatetime = new OriginalDate('2020-05-19T07:10:00+0000');
    dateSpy.mockImplementation((args: any) => {
      if (args === undefined) return currentDatetime;
      return new OriginalDate(args);
    });
    service.exposureStatus.append({
      lastChecked: {
        timestamp: new OriginalDate('2020-05-18T04:10:00+0000').getTime(),
        period: periodSinceEpoch(new OriginalDate('2020-05-18T04:10:00+0000'), HOURS_PER_PERIOD),
      },
    });

    const currentPeriod = periodSinceEpoch(currentDatetime, HOURS_PER_PERIOD);
    when(server.retrieveDiagnosisKeys)
      .calledWith(currentPeriod)
      .mockRejectedValue(null);

    await service.updateExposureStatus();

    expect(storage.setItem).toHaveBeenCalledWith(
      EXPOSURE_STATUS,
      expect.jsonStringContaining({
        lastChecked: {
          timestamp: currentDatetime.getTime(),
          period: currentPeriod - 1,
        },
      }),
    );
  });

  it('enters Diagnosed flow when start keys submission process', async () => {
    when(server.claimOneTimeCode)
      .calledWith('12345678')
      .mockResolvedValue({
        serverPublicKey: 'serverPublicKey',
        clientPrivateKey: 'clientPrivateKey',
        clientPublicKey: 'clientPublicKey',
      });

    await service.startKeysSubmission('12345678');
    expect(service.exposureStatus.get()).toStrictEqual(
      expect.objectContaining({
        type: ExposureStatusType.Diagnosed,
        cycleEndsAt: expect.any(Number),
        needsSubmission: true,
      }),
    );
  });

  it('restores "diagnosed" status from storage', async () => {
    when(storage.getItem)
      .calledWith(EXPOSURE_STATUS)
      .mockResolvedValueOnce(
        JSON.stringify({
          type: ExposureStatusType.Diagnosed,
          cycleStartsAt: new OriginalDate('2020-05-18T04:10:00+0000').toString(),
        }),
      );

    await service.start();

    expect(service.exposureStatus.get()).toStrictEqual(
      expect.objectContaining({
        type: ExposureStatusType.Diagnosed,
      }),
    );
  });

  it('needsSubmission status recalculates daily', async () => {
    let currentDateString = '2020-05-19T04:10:00+0000';

    service.exposureStatus.append({
      type: ExposureStatusType.Diagnosed,
      needsSubmission: false,
      cycleStartsAt: new OriginalDate('2020-05-14T04:10:00+0000').getTime(),
      cycleEndsAt: new OriginalDate('2020-05-28T04:10:00+0000').getTime(),
      submissionLastCompletedAt: null,
    });

    dateSpy.mockImplementation((...args) =>
      args.length > 0 ? new OriginalDate(...args) : new OriginalDate(currentDateString),
    );

    await service.start();
    await service.updateExposureStatus();
    expect(service.exposureStatus.get()).toStrictEqual(
      expect.objectContaining({type: ExposureStatusType.Diagnosed, needsSubmission: true}),
    );

    currentDateString = '2020-05-20T04:10:00+0000';
    when(secureStorage.get)
      .calledWith('submissionAuthKeys')
      .mockResolvedValueOnce('{}');
    await service.fetchAndSubmitKeys({dateType: 'noDate', date: null});

    expect(storage.setItem).toHaveBeenCalledWith(
      EXPOSURE_STATUS,
      expect.jsonStringContaining({
        submissionLastCompletedAt: new OriginalDate(currentDateString).getTime(),
      }),
    );

    expect(service.exposureStatus.get()).toStrictEqual(
      expect.objectContaining({type: ExposureStatusType.Diagnosed, needsSubmission: false}),
    );

    service.exposureStatus.append({
      submissionLastCompletedAt: new OriginalDate(currentDateString).getTime(),
    });

    // advance day forward
    currentDateString = '2020-05-21T04:10:00+0000';

    await service.updateExposureStatus();
    expect(service.exposureStatus.get()).toStrictEqual(
      expect.objectContaining({type: ExposureStatusType.Diagnosed, needsSubmission: true}),
    );

    // advance 14 days
    currentDateString = '2020-05-30T04:10:00+0000';
    service.exposureStatus.append({
      submissionLastCompletedAt: new OriginalDate('2020-05-28T04:10:00+0000').getTime(),
    });

    await service.updateExposureStatus();
    expect(service.exposureStatus.get()).toStrictEqual(expect.objectContaining({type: ExposureStatusType.Monitoring}));
  });

  describe('isReminderNeeded', () => {
    it('returns true when missing uploadReminderLastSentAt', async () => {
      const today = new OriginalDate('2020-05-18T04:10:00+0000');

      const status = {
        type: ExposureStatusType.Diagnosed,
        needsSubmission: true,
        // uploadReminderLastSentAt: new Date(), don't pass this
      };

      expect(service.isReminderNeeded(status)).toStrictEqual(true);
    });

    it('returns true when uploadReminderLastSentAt is a day old', async () => {
      const today = new OriginalDate('2020-05-18T04:10:00+0000');
      const lastSent = new OriginalDate('2020-05-17T04:10:00+0000');

      const status = {
        type: ExposureStatusType.Diagnosed,
        needsSubmission: true,
        uploadReminderLastSentAt: lastSent.getTime(),
      };

      expect(service.isReminderNeeded(status)).toStrictEqual(true);
    });

    it('returns false when uploadReminderLastSentAt is < 1 day old', async () => {
      const today = new OriginalDate('2020-05-18T04:10:00+0000');
      const lastSent = today;

      const status = {
        type: ExposureStatusType.Diagnosed,
        needsSubmission: true,
        uploadReminderLastSentAt: lastSent.getTime(),
      };

      expect(service.isReminderNeeded(status)).toStrictEqual(false);
    });
  });

  describe('updateExposureStatus', () => {
    it('keeps lastChecked when reset from diagnosed state to monitoring state', async () => {
      const today = new OriginalDate('2020-05-18T04:10:00+0000');

      const period = periodSinceEpoch(today, HOURS_PER_PERIOD);
      service.exposureStatus.set({
        type: ExposureStatusType.Diagnosed,
        cycleStartsAt: today.getTime() - 14 * 3600 * 24 * 1000,
        cycleEndsAt: today.getTime(),
        lastChecked: {
          period,
          timestamp: today.getTime() - ONE_DAY,
        },
      });

      await service.updateExposureStatus();

      expect(service.exposureStatus.get()).toStrictEqual(
        expect.objectContaining({
          lastChecked: {
            period,
            timestamp: today.getTime(),
          },
          type: ExposureStatusType.Monitoring,
        }),
      );
    });

    it.each([
      [1, ExposureStatusType.Exposed],
      [10, ExposureStatusType.Exposed],
      [14, ExposureStatusType.Monitoring],
      [20, ExposureStatusType.Monitoring],
    ])('if exposed %p days ago, state expected to be %p', async (daysAgo, expectedStatus) => {
      const today = new OriginalDate('2020-05-18T04:10:00+0000');
      const period = periodSinceEpoch(today, HOURS_PER_PERIOD);

      service.exposureStatus.set({
        type: ExposureStatusType.Exposed,
        lastChecked: {
          period,
          timestamp: today.getTime() - ONE_DAY,
        },
        summary: getSummary({
          today,
          hasMatchedKey: true,
          daysSinceLastExposure: daysAgo,
          attenuationDurations: [20, 0, 0],
        }),
      });

      await service.updateExposureStatus();

      expect(service.exposureStatus.get()).toStrictEqual(
        expect.objectContaining({
          lastChecked: {
            period,
            timestamp: today.getTime(),
          },
          type: expectedStatus,
        }),
      );
    });

    it('does not reset to monitoring state when lastExposureTimestamp is not available', async () => {
      const today = new OriginalDate('2020-05-18T04:10:00+0000');
      const period = periodSinceEpoch(today, HOURS_PER_PERIOD);
      service.exposureStatus.set({
        type: ExposureStatusType.Exposed,
        lastChecked: {
          period,
          timestamp: today.getTime(),
        },
        summary: {
          daysSinceLastExposure: 2,
          lastExposureTimestamp: 0,
          matchedKeyCount: 1,
          maximumRiskScore: 1,
        },
      });

      await service.updateExposureStatus();

      expect(service.exposureStatus.get()).toStrictEqual(
        expect.objectContaining({
          type: ExposureStatusType.Exposed,
          lastChecked: {
            period,
            timestamp: today.getTime(),
          },
          summary: {
            daysSinceLastExposure: 2,
            lastExposureTimestamp: 0,
            matchedKeyCount: 1,
            maximumRiskScore: 1,
          },
        }),
      );
    });

    it('selects next exposure summary if user is not already exposed', async () => {
      const period = periodSinceEpoch(today, HOURS_PER_PERIOD);
      const nextSummary = {
        daysSinceLastExposure: 7,
        lastExposureTimestamp: today.getTime() - 7 * 3600 * 24 * 1000,
        matchedKeyCount: 1,
        maximumRiskScore: 1,
        attenuationDurations: [1200, 0, 0],
      };
      bridge.detectExposure.mockResolvedValueOnce([nextSummary]);
      service.exposureStatus.set({
        type: ExposureStatusType.Monitoring,
        lastChecked: {
          period,
          timestamp: today.getTime() - DEFERRED_JOB_INTERNVAL_IN_MINUTES * 60 * 1000 - 3600 * 1000,
        },
      });

      await service.updateExposureStatus();

      expect(service.exposureStatus.get()).toStrictEqual(
        expect.objectContaining({
          type: ExposureStatusType.Exposed,
          summary: nextSummary,
        }),
      );
    });

    it('selects current exposure summary if user is already exposed', async () => {
      // abc
      const today = new OriginalDate('2020-05-18T04:10:00+0000');
      const period = periodSinceEpoch(today, HOURS_PER_PERIOD);
      const currentSummary = getSummary({
        today,
        hasMatchedKey: true,
        daysSinceLastExposure: 8,
        attenuationDurations: [17, 0, 0],
      });
      const nextSummary = getSummary({
        today,
        hasMatchedKey: true,
        daysSinceLastExposure: 7,
        attenuationDurations: [17, 0, 0],
      });

      service.exposureStatus.set({
        type: ExposureStatusType.Exposed,
        lastChecked: {
          period,
          timestamp: today.getTime() - 10 * 60 * 60 * 1000,
        },
        summary: currentSummary,
      });
      bridge.detectExposure.mockResolvedValueOnce([nextSummary]);

      await service.updateExposureStatus();

      expect(service.exposureStatus.get()).toStrictEqual(
        expect.objectContaining({
          type: ExposureStatusType.Exposed,
          summary: currentSummary,
        }),
      );
    });

    it('processes the push notification when exposed', async () => {
      service.exposureStatus.set({
        type: ExposureStatusType.Exposed,
      });

      await service.updateExposureStatusInBackground();

      expect(service.exposureStatus.get()).toStrictEqual(
        expect.objectContaining({
          notificationSent: true,
        }),
      );
    });

    it("doesn't send notification if status is Monitoring", async () => {
      service.exposureStatus.set({
        type: ExposureStatusType.Monitoring,
      });

      await service.updateExposureStatusInBackground();

      expect(service.exposureStatus.get()).toStrictEqual(
        expect.objectContaining({
          type: ExposureStatusType.Monitoring,
        }),
      );
      expect(PushNotification.presentLocalNotification).not.toHaveBeenCalled();
    });

    it('processes the reminder push notification when diagnosed', async () => {
      const today = new OriginalDate('2020-05-18T04:10:00+0000');
      const lastSent = new OriginalDate('2020-05-17T04:10:00+0000');
      service.exposureStatus.set({
        type: ExposureStatusType.Diagnosed,
        needsSubmission: true,
        uploadReminderLastSentAt: lastSent.getTime(),
        lastChecked: {
          period: periodSinceEpoch(today, HOURS_PER_PERIOD),
          timestamp: today.getTime() - 10 * 60 * 60 * 1000,
        },
      });

      await service.updateExposureStatusInBackground();

      expect(PushNotification.presentLocalNotification).toHaveBeenCalledTimes(1);

      expect(service.exposureStatus.get()).toStrictEqual(
        expect.objectContaining({
          uploadReminderLastSentAt: today.getTime(),
        }),
      );
    });
  });

  it('calculateNeedsSubmission when monitoring', () => {
    service.exposureStatus.set({
      type: ExposureStatusType.Monitoring,
    });
    expect(service.calculateNeedsSubmission()).toStrictEqual(false);
  });

  it('calculateNeedsSubmission when exposed', () => {
    const today = new OriginalDate();
    service.exposureStatus.set({
      type: ExposureStatusType.Exposed,
      summary: getSummary({
        today,
        hasMatchedKey: true,
        daysSinceLastExposure: 7,
        attenuationDurations: [20, 0, 0],
      }),
    });
    expect(service.calculateNeedsSubmission()).toStrictEqual(false);
  });

  it('calculateNeedsSubmission when diagnosed false', () => {
    const today = new OriginalDate();
    service.exposureStatus.set({
      type: ExposureStatusType.Diagnosed,
      cycleStartsAt: today.getTime() - 15 * ONE_DAY,
      cycleEndsAt: today.getTime() - ONE_DAY,
      needsSubmission: true,
    });
    dateSpy.mockImplementation((...args: any[]) => (args.length > 0 ? new OriginalDate(...args) : today));
    expect(service.calculateNeedsSubmission()).toStrictEqual(false);
  });

  it('calculateNeedsSubmission when diagnosed true', () => {
    const today = new OriginalDate();
    service.exposureStatus.set({
      type: ExposureStatusType.Diagnosed,
      cycleStartsAt: today.getTime() - 12 * ONE_DAY,
      cycleEndsAt: today.getTime() + 3 * ONE_DAY,
      needsSubmission: false,
    });
    expect(service.calculateNeedsSubmission()).toStrictEqual(true);
  });

  it('calculateNeedsSubmission when already submitted for that day false', () => {
    const today = new OriginalDate();
    service.exposureStatus.set({
      type: ExposureStatusType.Diagnosed,
      cycleStartsAt: today.getTime() - 10 * ONE_DAY,
      cycleEndsAt: today.getTime() + 4 * ONE_DAY,
      submissionLastCompletedAt: today.getTime(),
      needsSubmission: true,
    });

    expect(service.calculateNeedsSubmission()).toStrictEqual(false);
  });

  it('updateExposure, stay Monitoring', () => {
    service.exposureStatus.set({
      type: ExposureStatusType.Monitoring,
    });
    expect(service.updateExposure()).toStrictEqual(
      expect.objectContaining({
        type: ExposureStatusType.Monitoring,
      }),
    );
  });

  describe('getPeriodsSinceLastFetch', () => {
    it('returns an array of [0, runningPeriod] if _lastCheckedPeriod is undefined', () => {
      expect(service.getPeriodsSinceLastFetch()).toStrictEqual([0, 18400]);
    });

    it('returns an array of checkdates between lastCheckedPeriod and runningPeriod', () => {
      expect(service.getPeriodsSinceLastFetch(18395)).toStrictEqual([18400, 18399, 18398, 18397, 18396, 18395]);
    });

    it('returns an array of runningPeriod when current runningPeriod == _lastCheckedPeriod', () => {
      expect(service.getPeriodsSinceLastFetch(18400)).toStrictEqual([18400]);
    });

    it('returns an array of [runningPeriod, runningPeriod - 1] when current runningPeriod = _lastCheckedPeriod + 1', () => {
      expect(service.getPeriodsSinceLastFetch(18399)).toStrictEqual([18400, 18399]);
    });
  });

  describe('shouldPerformExposureCheck', () => {
    it('returns false if not onboarded', async () => {
      when(storage.getItem)
        .calledWith(Key.OnboardedDatetime)
        .mockResolvedValueOnce(false);

      const shouldPerformExposureCheck = await service.shouldPerformExposureCheck();

      expect(shouldPerformExposureCheck).toStrictEqual(false);
    });

    it('returns false if last check is too recent', async () => {
      service.exposureStatus.set({
        type: ExposureStatusType.Monitoring,
        lastChecked: {
          period: periodSinceEpoch(today, HOURS_PER_PERIOD),
          timestamp: today.getTime() - 60 * 60 * 1000,
        },
      });

      const shouldPerformExposureCheck = await service.shouldPerformExposureCheck();

      expect(shouldPerformExposureCheck).toStrictEqual(false);
    });

    it('returns true if last check is outside defined range', async () => {
      service.exposureStatus.set({
        type: ExposureStatusType.Monitoring,
        lastChecked: {
          period: periodSinceEpoch(today, HOURS_PER_PERIOD),
          timestamp: today.getTime() - 10 * 60 * 60 * 1000,
        },
      });

      const shouldPerformExposureCheck = await service.shouldPerformExposureCheck();

      expect(shouldPerformExposureCheck).toStrictEqual(true);
    });
  });
});
Example #21
Source File: mock_functions.tsx    From website with Apache License 2.0 4 votes vote down vote up
export function axios_mock(): void {
  // Mock all the async axios call.
  axios.get = jest.fn();
  axios.post = jest.fn();

  // get statsvar properties Median_Age_Person
  when(axios.get)
    .calledWith("/api/stats/stats-var-property?dcid=Median_Age_Person")
    .mockResolvedValue({
      data: {
        Median_Age_Person: {
          md: "",
          mprop: "age",
          pt: "Person",
          pvs: {},
          title: "Age",
        },
      },
    });

  // get statsvar properties Count_Person
  when(axios.get)
    .calledWith("/api/stats/stats-var-property?dcid=Count_Person")
    .mockResolvedValue({
      data: {
        Count_Person: {
          md: "",
          mprop: "count",
          pt: "Person",
          pvs: {},
          title: "Population",
        },
      },
    });

  // get statsVar info of Median_Age_Person and Count_Person
  when(axios.get)
    .calledWith(
      "/api/stats/stats-var-property?dcid=Median_Age_Person&dcid=Count_Person"
    )
    .mockResolvedValue({
      data: {
        Median_Age_Person: {
          md: "",
          mprop: "age",
          pt: "Person",
          pvs: {},
          title: "Age",
        },
        Count_Person: {
          md: "",
          mprop: "count",
          pt: "Person",
          pvs: {},
          title: "Population",
        },
      },
    });

  when(axios.get)
    .calledWith("/api/stats/stats-var-property?dcid=NotInTheTree")
    .mockResolvedValue({
      data: {
        NotInTheTree: {
          md: "",
          mprop: "count",
          pt: "Person",
          pvs: {},
          title: "",
        },
      },
    });

  // get place stats vars, geoId/05
  when(axios.post)
    .calledWith("/api/place/stat-vars/union", {
      dcids: ["geoId/05"],
      statVars: ["Median_Age_Person"],
    })
    .mockResolvedValue({
      data: ["Median_Age_Person"],
    });

  // get place stats vars, geoId/05
  when(axios.post)
    .calledWith("/api/place/stat-vars/union", {
      dcids: ["geoId/05"],
      statVars: ["Median_Age_Person", "Count_Person"],
    })
    .mockResolvedValue({
      data: ["Count_Person", "Median_Age_Person"],
    });

  // get place stats vars, geoId/05
  when(axios.post)
    .calledWith("/api/place/stat-vars/union", {
      dcids: ["geoId/05"],
      statVars: ["NotInTheTree"],
    })
    .mockResolvedValue({
      data: ["NotInTheTree"],
    });

  // get place stats vars, geoId/05
  when(axios.post)
    .calledWith("/api/place/stat-vars/union", {
      dcids: ["geoId/05"],
      statVars: ["Count_Person"],
    })
    .mockResolvedValue({
      data: ["Count_Person"],
    });

  // get place names, geoId/05
  when(axios.get)
    .calledWith("/api/place/name?dcid=geoId/05")
    .mockResolvedValue({ data: { "geoId/05": "Place" } });

  // get data, geoId/05, Median_Age_Person
  when(axios.post)
    .calledWith("/api/stats", {
      statVars: ["Median_Age_Person"],
      places: ["geoId/05"],
    })
    .mockResolvedValue({
      data: {
        "geoId/05": {
          data: {
            Median_Age_Person: {
              val: {
                "2015": 37.7,
                "2016": 37.7,
                "2017": 37.9,
                "2018": 37.9,
                "2013": 37.5,
                "2012": 37.4,
                "2014": 37.6,
                "2019": 38.1,
                "2011": 37.3,
              },
              metadata: {
                importName: "CensusACS5YearSurvey",
                provenanceUrl: "https://www.census.gov/",
                measurementMethod: "CensusACS5yrSurvey",
                unit: "Year",
              },
            },
          },
        },
      },
    });

  // get data, geoId/05,Count_Person
  when(axios.post)
    .calledWith("/api/stats", {
      statVars: ["Count_Person"],
      places: ["geoId/05"],
    })
    .mockResolvedValue({
      data: {
        "geoId/05": {
          data: {
            Count_Person: {
              val: {
                "2001": 2690743,
                "2012": 2952164,
              },
              metadata: {
                importName: "CensusPEP",
                provenanceUrl:
                  "https://www.census.gov/programs-surveys/popest.html",
                measurementMethod: "CensusPEPSurvey",
              },
            },
          },
        },
      },
    });

  when(axios.post)
    .calledWith("/api/stats", {
      statVars: ["NotInTheTree"],
      places: ["geoId/05"],
    })
    .mockResolvedValue({
      data: {
        "geoId/05": {
          data: {
            NotInTheTree: {
              val: {
                "2001": 2690743,
                "2012": 2952164,
              },
              metadata: {
                importName: "CensusPEP",
                provenanceUrl:
                  "https://www.census.gov/programs-surveys/popest.html",
                measurementMethod: "CensusPEPSurvey",
              },
            },
          },
        },
      },
    });

  // get stats all data, geoId/05,Median_Age_Person
  when(axios.get)
    .calledWith("/api/stats/all?places=geoId/05&statVars=Median_Age_Person")
    .mockResolvedValue({
      placeData: {
        "geoId/05": {
          statVarData: {
            Count_Person: {
              sourceSeries: [
                {
                  val: {
                    "2015": 37.7,
                    "2016": 37.7,
                    "2017": 37.9,
                    "2018": 37.9,
                    "2013": 37.5,
                    "2012": 37.4,
                    "2014": 37.6,
                    "2019": 38.1,
                    "2011": 37.3,
                  },
                  importName: "CensusACS5YearSurvey",
                  provenanceUrl: "https://www.census.gov/",
                  measurementMethod: "CensusACS5yrSurvey",
                  unit: "Year",
                },
              ],
            },
          },
        },
      },
    });

  // get stats all data, geoId/05,Count_Person
  when(axios.get)
    .calledWith("/api/stats/all?places=geoId/05&statVars=Count_Person")
    .mockResolvedValue({
      placeData: {
        "geoId/05": {
          statVarData: {
            Count_Person: {
              sourceSeries: [
                {
                  val: {
                    "2001": 2690743,
                    "2012": 2952164,
                  },
                  importName: "CensusPEP",
                  provenanceUrl:
                    "https://www.census.gov/programs-surveys/popest.html",
                  measurementMethod: "CensusPEPSurvey",
                },
              ],
            },
          },
        },
      },
    });

  when(axios.get)
    .calledWith("/api/stats/all?places=geoId/05&statVars=NotInTheTree")
    .mockResolvedValue({
      placeData: {
        "geoId/05": {
          statVarData: {
            NotInTheTree: {
              sourceSeries: [
                {
                  val: {
                    "2001": 2690743,
                    "2012": 2952164,
                  },
                  importName: "CensusPEP",
                  provenanceUrl:
                    "https://www.census.gov/programs-surveys/popest.html",
                  measurementMethod: "CensusPEPSurvey",
                },
              ],
            },
          },
        },
      },
    });

  when(axios.get)
    .calledWith("/api/place/displayname?dcid=geoId/05")
    .mockResolvedValue({
      data: {
        "geoId/05": "Arkansas",
      },
    });
  when(axios.get)
    .calledWith("/api/stats/stat-var-group?stat_var_group=dc/g/Root")
    .mockResolvedValue({
      data: {
        childStatVarGroups: [
          {
            displayName: "Demographics",
            id: "dc/g/Demographics",
            specializedEntity: "Demographics",
            descendentStatVarCount: 100,
          },
          {
            displayName: "Economics",
            id: "dc/g/Economics",
            specializedEntity: "Economics",
            descendentStatVarCount: 100,
          },
        ],
      },
    });
  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc%2Fg%2FDemographics&places=geoId/05"
    )
    .mockResolvedValue({
      data: {
        childStatVarGroups: [
          {
            displayName: "Person By Age",
            id: "dc/g/Person_Age",
            specializedEntity: "Age",
            descendentStatVarCount: 5,
          },
          {
            displayName: "Person By ArmedForcesStatus",
            id: "dc/g/Person_ArmedForcesStatus",
            specializedEntity: "ArmedForcesStatus",
            descendentStatVarCount: 5,
          },
        ],
        childStatVars: [
          {
            displayName: "Count Of Person",
            id: "Count_Person",
            searchName: "Count Of Person",
            hasData: true,
          },
          {
            displayName: "Median age of person",
            id: "Median_Age_Person",
            searchName: "Median age of person",
            hasData: true,
          },
        ],
      },
    });
  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc/g/Root&places=geoId/05"
    )
    .mockResolvedValue({
      data: {
        childStatVarGroups: [
          {
            displayName: "Demographics",
            id: "dc/g/Demographics",
            specializedEntity: "Demographics",
            descendentStatVarCount: 100,
          },
          {
            displayName: "Economics",
            id: "dc/g/Economics",
            specializedEntity: "Economics",
            descendentStatVarCount: 100,
          },
        ],
      },
    });

  when(axios.get)
    .calledWith("/api/stats/stat-var-path?id=Count_Person")
    .mockResolvedValue({
      data: {
        path: ["Count_Person", "dc/g/Demographics"],
      },
    });

  when(axios.get)
    .calledWith("/api/stats/stat-var-path?id=Median_Age_Person")
    .mockResolvedValue({
      data: {
        path: ["Median_Age_Person", "dc/g/Demographics"],
      },
    });

  when(axios.get)
    .calledWith("/api/stats/stat-var-path?id=NotInTheTree")
    .mockResolvedValue({
      data: {
        path: ["NotInTheTree"],
      },
    });

  when(axios.post)
    .calledWith("/api/stats/stat-var-summary", {
      statVars: ["Count_Person", "Median_Age_Person"],
    })
    .mockResolvedValue({
      data: {
        statVarSummary: {
          Count_Person: {
            placeTypeSummary: {
              type1: {
                numPlaces: 0,
                topPlaces: [],
              },
            },
          },
          Median_Age_Person: {
            placeTypeSummary: {
              type1: {
                numPlaces: 0,
                topPlaces: [],
              },
            },
          },
        },
      },
    });
}
Example #22
Source File: app.test.tsx    From website with Apache License 2.0 4 votes vote down vote up
function mockAxios(): () => void {
  const get = axios.get;
  axios.get = jest.fn();

  // Counties in Delaware
  when(axios.get)
    .calledWith(`/api/place/places-in-names?dcid=geoId/10&placeType=County`)
    .mockResolvedValue({
      data: {
        "geoId/10001": "Kent County",
        "geoId/10003": "New Castle County",
        "geoId/10005": "Sussex County",
      },
    });

  // Population and statvar data
  const data = {
    Count_Person_Employed: {
      metadata: {
        BLS_LAUS: {
          provenanceUrl: "https://www.bls.gov/lau/",
          measurementMethod: "BLSSeasonallyUnadjusted",
        },
      },
      stat: {
        "geoId/10001": {
          date: "2016",
          metadata: {
            importName: "BLS_LAUS",
          },
          value: 76726,
        },
        "geoId/10003": {
          date: "2016",
          metadata: {
            importName: "BLS_LAUS",
          },
          value: 276517,
        },
        "geoId/10005": {
          date: "2016",
          metadata: {
            importName: "BLS_LAUS",
          },
          value: 104845,
        },
      },
    },
    Count_Establishment: {
      metadata: {
        CensusCountyBusinessPatterns: {
          provenanceUrl: "https://www.census.gov/",
          measurementMethod: "CensusCBPSurvey",
        },
      },
      stat: {
        "geoId/10001": {
          date: "2016",
          metadata: {
            importName: "CensusCountyBusinessPatterns",
          },
          value: 3422,
        },
        "geoId/10003": {
          date: "2016",
          metadata: {
            importName: "CensusCountyBusinessPatterns",
          },
          value: 16056,
        },
        "geoId/10005": {
          date: "2016",
          metadata: {
            importName: "CensusCountyBusinessPatterns",
          },
          value: 5601,
        },
      },
    },
    Count_HousingUnit: {
      metadata: {
        CensusACS5YearSurvey: {
          provenanceUrl: "https://www.census.gov/",
          measurementMethod: "CensusACS5yrSurvey",
        },
      },
      stat: {
        "geoId/10001": {
          date: "2016",
          metadata: {
            importName: "CensusACS5YearSurvey",
          },
          value: 70576,
        },
        "geoId/10003": {
          date: "2016",
          metadata: {
            importName: "CensusACS5YearSurvey",
          },
          value: 222146,
        },
        "geoId/10005": {
          date: "2016",
          metadata: {
            importName: "CensusACS5YearSurvey",
          },
          value: 135529,
        },
      },
    },
  };

  const rootGroupsData = {
    data: {
      childStatVarGroups: [
        {
          displayName: "Demographics",
          id: "dc/g/Demographics",
          specializedEntity: "Demographics",
          descendentStatVarCount: 2,
        },
        {
          displayName: "Economics",
          id: "dc/g/Economics",
          specializedEntity: "Economics",
          descendentStatVarCount: 2,
        },
      ],
    },
  };

  const demographicsGroupsData = {
    data: {
      childStatVarGroups: [
        {
          displayName: "Person By Age",
          id: "dc/g/Person_Age",
          specializedEntity: "Age",
          descendentStatVarCount: 2,
        },
        {
          displayName: "Person By ArmedForcesStatus",
          id: "dc/g/Person_ArmedForcesStatus",
          specializedEntity: "ArmedForcesStatus",
          descendentStatVarCount: 2,
        },
      ],
      childStatVars: [
        {
          displayName: "Count Employed",
          id: "Count_Person_Employed",
          searchName: "Count Of Person Employed",
          hasData: true,
        },
        {
          displayName: "Count Housing Unit",
          id: "Count_HousingUnit",
          searchName: "Count Housing Unit",
          hasData: true,
        },
        {
          displayName: "Count Establishment",
          id: "Count_Establishment",
          searchName: "Count Establishment",
          hasData: true,
        },
      ],
    },
  };

  const statVarInfoData = {
    data: {
      Count_Person_Employed: {
        title: "Employed",
      },
      Count_Establishment: {
        title: "Number Of Establishments",
      },
      Count_HousingUnit: {
        title: "Housing Units",
      },
    },
  };

  const pathsData = {
    Count_Person_Employed: {
      path: ["Count_Person_Employed", "dc/g/Demographics"],
    },
    Count_Establishment: {
      path: ["Count_Establishment", "dc/g/Economics"],
    },
    Count_HousingUnit: {
      path: ["Count_HousingUnit", "dc/g/Demographics"],
    },
  };

  when(axios.get)
    .calledWith(
      "/api/stats/within-place?parent_place=geoId/10&child_type=County" +
        "&stat_vars=Count_Person_Employed&stat_vars=Count_Establishment"
    )
    .mockResolvedValue({
      data: {
        Count_Person_Employed: data.Count_Person_Employed,
        Count_Establishment: data.Count_Establishment,
      },
    });
  when(axios.get)
    .calledWith(
      "/api/stats/within-place?parent_place=geoId/10&child_type=County" +
        "&stat_vars=Count_Person_Employed&stat_vars=Count_HousingUnit"
    )
    .mockResolvedValue({
      data: {
        Count_Person_Employed: data.Count_Person_Employed,
        Count_HousingUnit: data.Count_HousingUnit,
      },
    });
  const post = axios.post;
  axios.post = jest.fn();

  when(axios.post)
    .calledWith("/api/stats/Count_Person", {
      dcid: ["geoId/10001", "geoId/10003", "geoId/10005"],
    })
    .mockResolvedValue({
      data: {
        "geoId/10001": {
          data: {
            "2016": 180786,
          },
          placeName: "Kent County",
          provenanceUrl: "https://www.census.gov/programs-surveys/popest.html",
        },
        "geoId/10003": {
          data: {
            "2016": 558753,
          },
          placeName: "Kent County",
          provenanceUrl: "https://www.census.gov/programs-surveys/popest.html",
        },
        "geoId/10005": {
          data: {
            "2016": 234225,
          },
          placeName: "Kent County",
          provenanceUrl: "https://www.census.gov/programs-surveys/popest.html",
        },
      },
    });

  when(axios.get)
    .calledWith("/api/place/parent/geoId/10")
    .mockResolvedValue({
      data: ["country/USA"],
    });

  when(axios.get).calledWith("/api/place/type/geoId/10").mockResolvedValue({
    data: "State",
  });

  when(axios.get)
    .calledWith("/api/place/places-in?dcid=geoId/10&placeType=County")
    .mockResolvedValue({
      data: {
        "geoId/10": ["geoId/10001", "geoId/10003", "geoId/10005"],
      },
    });

  when(axios.get)
    .calledWith("/api/stats/stat-var-group?stat_var_group=dc/g/Root")
    .mockResolvedValue(rootGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc/g/Root&places=geoId/10001&places=geoId/10003&places=geoId/10005"
    )
    .mockResolvedValue(rootGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc/g/Root&places=geoId/10001&places=geoId/10005&places=geoId/10003"
    )
    .mockResolvedValue(rootGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc/g/Root&places=geoId/10003&places=geoId/10001&places=geoId/10005"
    )
    .mockResolvedValue(rootGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc/g/Root&places=geoId/10003&places=geoId/10005&places=geoId/10001"
    )
    .mockResolvedValue(rootGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc/g/Root&places=geoId/10005&places=geoId/10003&places=geoId/10001"
    )
    .mockResolvedValue(rootGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc/g/Root&places=geoId/10005&places=geoId/10001&places=geoId/10003"
    )
    .mockResolvedValue(rootGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc%2Fg%2FDemographics&places=geoId/10001&places=geoId/10003&places=geoId/10005"
    )
    .mockResolvedValue(demographicsGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc%2Fg%2FDemographics&places=geoId/10001&places=geoId/10005&places=geoId/10003"
    )
    .mockResolvedValue(demographicsGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc%2Fg%2FDemographics&places=geoId/10003&places=geoId/10001&places=geoId/10005"
    )
    .mockResolvedValue(demographicsGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc%2Fg%2FDemographics&places=geoId/10003&places=geoId/10005&places=geoId/10001"
    )
    .mockResolvedValue(demographicsGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc%2Fg%2FDemographics&places=geoId/10005&places=geoId/10003&places=geoId/10001"
    )
    .mockResolvedValue(demographicsGroupsData);

  when(axios.get)
    .calledWith(
      "/api/stats/stat-var-group?stat_var_group=dc%2Fg%2FDemographics&places=geoId/10005&places=geoId/10001&places=geoId/10003"
    )
    .mockResolvedValue(demographicsGroupsData);

  when(axios.get)
    .calledWith("/api/stats/stats-var-property?dcid=Count_Establishment")
    .mockResolvedValue(statVarInfoData);

  when(axios.get)
    .calledWith("/api/stats/stats-var-property?dcid=Count_HousingUnit")
    .mockResolvedValue(statVarInfoData);

  when(axios.get)
    .calledWith("/api/stats/stats-var-property?dcid=Count_Person_Employed")
    .mockResolvedValue(statVarInfoData);

  when(axios.get)
    .calledWith("/api/stats/stat-var-path?id=Count_Establishment")
    .mockResolvedValue({ data: pathsData.Count_Establishment });

  when(axios.get)
    .calledWith("/api/stats/stat-var-path?id=Count_HousingUnit")
    .mockResolvedValue({ data: pathsData.Count_HousingUnit });

  when(axios.get)
    .calledWith("/api/stats/stat-var-path?id=Count_Person_Employed")
    .mockResolvedValue({ data: pathsData.Count_Person_Employed });

  when(axios.post)
    .calledWith("/api/stats/stat-var-summary", {
      statVars: [
        "Count_Person_Employed",
        "Count_HousingUnit",
        "Count_Establishment",
      ],
    })
    .mockResolvedValue({
      data: {
        statVarSummary: {
          Count_Person_Employed: {
            placeTypeSummary: {
              type1: {
                numPlaces: 0,
                topPlaces: [],
              },
            },
          },
          Count_HousingUnit: {
            placeTypeSummary: {
              type1: {
                numPlaces: 0,
                topPlaces: [],
              },
            },
          },
          Count_Establishment: {
            placeTypeSummary: {
              type1: {
                numPlaces: 0,
                topPlaces: [],
              },
            },
          },
        },
      },
    });
  return () => {
    axios.get = get;
    axios.post = post;
  };
}
Example #23
Source File: index.test.tsx    From oasis-wallet-web with Apache License 2.0 4 votes vote down vote up
describe('<Transaction  />', () => {
  let store: ReturnType<typeof configureAppStore>
  const ref = 'sourceAddr'
  const transaction = {
    amount: 1000000,
    timestamp: 1618018255,
    from: 'source',
    to: 'destination',
    type: transactionTypes.TransactionType.StakingTransfer,
    hash: 'ff1234',
  } as transactionTypes.Transaction
  const network = 'mainnet'

  beforeEach(() => {
    jest.mocked(backend).mockImplementation(() => BackendAPIs.OasisScan)
    store = configureAppStore()

    when(useSelector as any)
      .calledWith(selectTicker)
      .mockReturnValue('TEST')
  })

  it('should match snapshot', () => {
    const component = renderComponent(store, ref, transaction, network)
    expect(component.container.firstChild).toMatchSnapshot()
  })

  it('should redirect user when clicking on address section', () => {
    renderComponent(store, ref, transaction, network)

    userEvent.click(screen.getByLabelText('ContactInfo'))
    expect(pushSpy).toHaveBeenCalledWith(
      expect.objectContaining({
        pathname: `/account/${transaction.from}`,
      }),
    )
  })

  it('should not redirect user when clicking on amount or block section', () => {
    renderComponent(store, ref, transaction, network)

    userEvent.click(screen.getByLabelText('Money'))
    userEvent.click(screen.getByLabelText('Cube'))
    expect(pushSpy).not.toHaveBeenCalled()
  })

  it('should handle unknown transaction types gracefully', () => {
    const component = renderComponent(
      store,
      'sourceAddr',
      {
        amount: 1000000,
        timestamp: 1618018255,
        from: 'source',
        to: 'destination',
        type: 'turboencabulate' as transactionTypes.TransactionType,
        hash: 'ff1234',
        fee: undefined,
        level: undefined,
        status: true,
      },
      network,
    )
    expect(component.container.firstChild).toMatchSnapshot()
  })

  it('should not render a link when address is undefined', () => {
    renderComponent(
      store,
      'sourceAddr',
      {
        amount: 1000000,
        timestamp: 1618018255,
        from: 'sourceAddr',
        to: undefined,
        type: 'anyType' as transactionTypes.TransactionType,
        hash: 'ff1234',
        fee: undefined,
        level: undefined,
        status: true,
      },
      network,
    )

    expect(screen.queryByTestId('external-wallet-address')).not.toBeInTheDocument()
    expect(screen.getByText('common.unavailable')).toBeInTheDocument()
  })

  it('should render testnet link', () => {
    renderComponent(store, ref, transaction, 'testnet')
    expect(screen.getByTestId('explorer-link')).toHaveAttribute(
      'href',
      'https://testnet.oasisscan.com/transactions/ff1234',
    )
  })

  it('should render monitor link', () => {
    jest.mocked(backend).mockImplementation(() => BackendAPIs.OasisMonitor)
    renderComponent(store, ref, transaction, network)
    expect(screen.getByTestId('explorer-link')).toHaveAttribute(
      'href',
      'https://oasismonitor.com/operation/ff1234',
    )
  })

  it('should render testnet monitor link', () => {
    jest.mocked(backend).mockImplementation(() => BackendAPIs.OasisMonitor)
    renderComponent(store, ref, transaction, 'testnet')
    expect(screen.getByTestId('explorer-link')).toHaveAttribute(
      'href',
      'https://testnet.oasismonitor.com/operation/ff1234',
    )
  })
})
Example #24
Source File: run.test.ts    From gh-action-auto-merge-dependency-updates with MIT License 4 votes vote down vote up
describe('run', () => {
  beforeEach(() => {
    jest.useFakeTimers('modern').setSystemTime(0);
    (github as any).context = {};
  });

  afterEach(() => jest.useRealTimers());

  it('stops if the event name is unknown', async () => {
    github.context.eventName = 'unknown';
    expect(await run()).toBe(Result.UnknownEvent);
  });

  ['pull_request', 'pull_request_target', 'pull_request_review'].forEach(
    (name) => {
      describe(`when the event name is ${name}`, () => {
        let mockAllowedActors: string;
        let mockAllowedUpdateTypes: string;
        let mockApprove: string;
        let mockMerge: string;
        let mockMergeMethod: string;
        let mockPackageBlockList: string;
        let mockPackageAllowList: string | undefined;

        beforeEach(() => {
          github.context.eventName = name;
          mockAllowedActors = '';
          mockAllowedUpdateTypes = '';
          mockApprove = '';
          mockMerge = '';
          mockMergeMethod = 'merge';
          mockPackageBlockList = '';
          mockPackageAllowList = undefined;

          (core.setOutput as any).mockReset();
          const getInputMock = when(core.getInput as any).mockImplementation(
            () => {
              throw new Error('Unexpected call');
            }
          );
          getInputMock
            .calledWith('repo-token', { required: true })
            .mockReturnValue('token');
          getInputMock
            .calledWith('allowed-actors', { required: true })
            .mockImplementation(() => mockAllowedActors);
          getInputMock
            .calledWith('allowed-update-types', { required: true })
            .mockImplementation(() => mockAllowedUpdateTypes);
          getInputMock
            .calledWith('approve')
            .mockImplementation(() => mockApprove);
          getInputMock
            .calledWith('package-block-list')
            .mockImplementation(() => mockPackageBlockList);
          getInputMock
            .calledWith('package-allow-list')
            .mockImplementation(() => mockPackageAllowList);
          getInputMock.calledWith('merge').mockImplementation(() => mockMerge);
          getInputMock
            .calledWith('merge-method', { required: true })
            .mockImplementation(() => mockMergeMethod);
        });

        it('stops if the actor is not in the allow list', async () => {
          github.context.actor = 'unknown';
          expect(await run()).toBe(Result.ActorNotAllowed);
        });

        describe('with an allowed actor', () => {
          let mockPackageJsonPr: any;
          let mockPackageJsonBase: any;
          let mockCompareCommits: any;
          let mockPr: any;
          let reviewSubmitted: boolean;
          let reposGetContentMock: jest.Mock;
          let validMergeCallMock: jest.Mock;
          const mockSha = 'headSha';

          beforeEach(() => {
            mockAllowedActors = 'actor1, actor2';
            mockPackageJsonPr = {};
            mockPackageJsonBase = {};
            reviewSubmitted = false;

            github.context.actor = 'actor2';
            (github.context as any).repo = {
              owner: 'repoOwner',
              repo: 'repo ',
            };
            (github.context as any).payload = {
              pull_request: {
                number: 1,
                base: {
                  sha: 'baseSha',
                },
                head: {
                  sha: mockSha,
                },
              },
            };
            mockCompareCommits = {
              data: {
                files: [
                  { filename: 'package.json', status: 'modified' },
                  { filename: 'package-lock.json', status: 'modified' },
                  { filename: 'yarn.lock', status: 'modified' },
                ],
              },
            };
            mockPr = {
              data: {
                state: 'open',
                mergeable: true,
                head: { sha: mockSha },
              },
            };

            reposGetContentMock = jest.fn();
            when(reposGetContentMock)
              .mockImplementation(() => {
                throw new Error('Unexpected call');
              })
              .calledWith({
                owner: github.context.repo.owner,
                repo: github.context.repo.repo,
                path: 'package.json',
                ref: (github.context.payload.pull_request as any).head.sha,
              })
              .mockImplementation(() =>
                Promise.resolve({
                  data: {
                    type: 'file',
                    encoding: 'base64',
                    content: Buffer.from(
                      JSON.stringify(mockPackageJsonPr, null, 2)
                    ).toString('base64'),
                  },
                })
              )
              .calledWith({
                owner: github.context.repo.owner,
                repo: github.context.repo.repo,
                path: 'package.json',
                ref: (github.context.payload.pull_request as any).base.sha,
              })
              .mockImplementation(() =>
                Promise.resolve({
                  data: {
                    type: 'file',
                    encoding: 'base64',
                    content: Buffer.from(
                      JSON.stringify(mockPackageJsonBase, null, 2)
                    ).toString('base64'),
                  },
                })
              );

            const pullsGetMock = jest.fn();
            when(pullsGetMock)
              .expectCalledWith({
                owner: github.context.repo.owner,
                repo: github.context.repo.repo,
                pull_number: github.context.payload.pull_request!.number,
              })
              .mockImplementation(() => mockPr);

            const reposCompareCommitsMock = jest.fn();
            when(reposCompareCommitsMock)
              .expectCalledWith({
                owner: github.context.repo.owner,
                repo: github.context.repo.repo,
                base: (github.context.payload.pull_request as any).base.sha,
                head: (github.context.payload.pull_request as any).head.sha,
              })
              .mockImplementation(() => mockCompareCommits);

            const mockReviewId = 'mockReviewId';
            const createReviewMock = jest.fn();
            when(createReviewMock)
              .expectCalledWith({
                owner: github.context.repo.owner,
                repo: github.context.repo.repo,
                pull_number: github.context.payload.pull_request!.number,
                commit_id: mockSha,
              })
              .mockReturnValue(Promise.resolve({ data: { id: mockReviewId } }));

            const submitReviewMock = jest.fn();
            when(submitReviewMock)
              .expectCalledWith({
                owner: github.context.repo.owner,
                repo: github.context.repo.repo,
                pull_number: github.context.payload.pull_request!.number,
                review_id: mockReviewId,
                event: 'APPROVE',
              })
              .mockImplementation(() => {
                reviewSubmitted = true;
                return Promise.resolve();
              });

            const mergeMock = jest.fn();
            validMergeCallMock = jest.fn();
            when(mergeMock)
              .expectCalledWith({
                owner: github.context.repo.owner,
                repo: github.context.repo.repo,
                pull_number: github.context.payload.pull_request!.number,
                merge_method: mockMergeMethod,
                sha: mockSha,
              })
              .mockImplementation(validMergeCallMock);

            const octokitMock = {
              repos: {
                getContent: reposGetContentMock,
                compareCommits: reposCompareCommitsMock,
              },
              pulls: {
                get: pullsGetMock,
                createReview: createReviewMock,
                submitReview: submitReviewMock,
                merge: mergeMock,
              },
            };

            const getOctokitOptionsReturn = Symbol('getOctokitOptionsReturn');
            when((githubUtils as any).getOctokitOptions)
              .expectCalledWith('token', {
                throttle: expect.objectContaining({
                  onRateLimit: expect.any(Function),
                  onAbuseLimit: expect.any(Function),
                }),
              })
              .mockReturnValue(getOctokitOptionsReturn);

            const octokitMockBuilder = jest.fn();
            when(octokitMockBuilder)
              .expectCalledWith(getOctokitOptionsReturn)
              .mockReturnValue(octokitMock);

            when((githubUtils.GitHub as any).plugin)
              .expectCalledWith(throttling)
              .mockReturnValue(octokitMockBuilder);
          });

          it('errors if allowed-update-types invalid', async () => {
            mockAllowedUpdateTypes = 'invalid';
            await expect(run()).rejects.toHaveProperty(
              'message',
              'allowed-update-types invalid'
            );
          });

          it('errors if merge-method invalid', async () => {
            mockMergeMethod = 'invalid';
            await expect(run()).rejects.toHaveProperty(
              'message',
              'merge-method invalid: invalid'
            );
          });

          it('errors if the content type is incorrect', async () => {
            reposGetContentMock.mockReturnValue(
              Promise.resolve({ data: { type: 'unknown' } })
            );
            await expect(run()).rejects.toHaveProperty(
              'message',
              'Unexpected repo content response'
            );
          });

          it('errors if the content encoding is incorrect', async () => {
            reposGetContentMock.mockReturnValue(
              Promise.resolve({ data: { type: 'file', encoding: 'unknown' } })
            );
            await expect(run()).rejects.toHaveProperty(
              'message',
              'Unexpected repo content response'
            );
          });

          it('stops if more than the allowed files change', async () => {
            mockCompareCommits.data.files = [
              { filename: 'something', status: 'modified' },
            ];
            expect(await run()).toBe(Result.FileNotAllowed);

            mockCompareCommits.data.files = [
              { filename: 'package.json', status: 'modified' },
              { filename: 'something', status: 'modified' },
            ];
            expect(await run()).toBe(Result.FileNotAllowed);
          });

          it('stops if an allowed file is changed but not modified', async () => {
            mockCompareCommits.data.files = [
              { filename: 'package.json', status: 'something' },
            ];
            expect(await run()).toBe(Result.FileNotAllowed);
          });

          it('stops if the diff of the package.json contains additions', async () => {
            mockPackageJsonPr = { addition: true };
            expect(await run()).toBe(Result.UnexpectedChanges);
          });

          it('stops if the diff of the package.json contains removals', async () => {
            mockPackageJsonBase = { addition: true };
            expect(await run()).toBe(Result.UnexpectedChanges);
          });

          it('stops if the diff of the package.json contains changes to something other than dependencies or devDependencies', async () => {
            mockPackageJsonBase.name = 'something';
            mockPackageJsonPr.name = 'somethingElse';
            expect(await run()).toBe(Result.UnexpectedPropertyChange);
          });

          it('stops if one of the updates is in the package block list', async () => {
            mockAllowedUpdateTypes = 'dependencies: patch';
            mockPackageBlockList = 'dep1, dep2';

            mockPackageJsonBase.dependencies = {
              dep1: '1.2.3',
            };
            mockPackageJsonPr.dependencies = {
              dep1: '1.2.4',
            };
            expect(await run()).toBe(Result.VersionChangeNotAllowed);

            mockPackageJsonBase.dependencies = {
              dep1: '1.2.3',
              dep2: '1.2.3',
            };
            mockPackageJsonPr.dependencies = {
              dep1: '1.2.4',
              dep2: '1.2.4',
            };
            expect(await run()).toBe(Result.VersionChangeNotAllowed);

            mockPackageJsonBase.dependencies = {
              dep1: '1.2.3',
              something: '1.2.3',
            };
            mockPackageJsonPr.dependencies = {
              dep1: '1.2.4',
              something: '1.2.4',
            };
            expect(await run()).toBe(Result.VersionChangeNotAllowed);
          });

          it('stops if one of the updates is not in the package allow list', async () => {
            mockAllowedUpdateTypes = 'dependencies: patch';
            mockPackageAllowList = 'dep1, dep2';

            mockPackageJsonBase.dependencies = {
              something: '1.2.3',
            };
            mockPackageJsonPr.dependencies = {
              something: '1.2.4',
            };
            expect(await run()).toBe(Result.VersionChangeNotAllowed);

            mockPackageJsonBase.dependencies = {
              dep1: '1.2.3',
              something: '1.2.3',
            };
            mockPackageJsonPr.dependencies = {
              dep1: '1.2.4',
              something: '1.2.4',
            };
            expect(await run()).toBe(Result.VersionChangeNotAllowed);
          });

          versionChanges.forEach(({ before, after, minRequired }) => {
            describe(`with an update from ${JSON.stringify(
              before
            )} to "${JSON.stringify(after)}"`, () => {
              beforeEach(() => {
                if (before.dev) {
                  mockPackageJsonBase.devDependencies = before.dev;
                }
                if (before.prod) {
                  mockPackageJsonBase.dependencies = before.prod;
                }
                if (after.dev) {
                  mockPackageJsonPr.devDependencies = after.dev;
                }
                if (after.prod) {
                  mockPackageJsonPr.dependencies = after.prod;
                }
              });

              allowedUpdateTypeCombinations.forEach(
                ({ allowedUpdateTypes, maxBump }) => {
                  describe(`with allowedUpdateTypes of "${allowedUpdateTypes}"`, () => {
                    beforeEach(() => {
                      mockAllowedUpdateTypes = allowedUpdateTypes;
                    });

                    if (
                      bumpTypes.indexOf(maxBump.dev) <
                        bumpTypes.indexOf(minRequired.dev) ||
                      bumpTypes.indexOf(maxBump.prod) <
                        bumpTypes.indexOf(minRequired.prod)
                    ) {
                      it('stops', async () => {
                        expect(await run()).toBe(
                          Result.VersionChangeNotAllowed
                        );
                      });

                      it('does not set the "success" output', async () => {
                        await run();
                        expect(core.setOutput).not.toHaveBeenCalledWith(
                          'success',
                          'true'
                        );
                      });
                    } else {
                      it('sets the "success" output', async () => {
                        await run();
                        expect(core.setOutput).toHaveBeenCalledWith(
                          'success',
                          'true'
                        );
                      });

                      [true, false].forEach((approve) => {
                        describe(`when approve option is ${
                          approve ? 'enabled' : 'disabled'
                        }`, () => {
                          if (approve) {
                            it('approves the PR', async () => {
                              mockApprove = 'true';
                              expect(await run()).toBe(Result.PRMergeSkipped);
                            });
                          } else {
                            it('does not approve the PR', async () => {
                              expect(await run()).toBe(Result.PRMergeSkipped);
                              expect(reviewSubmitted).toBe(false);
                            });
                          }

                          describe('when merge option is disabled', () => {
                            it('completes and does not merge the PR', async () => {
                              expect(await run()).toBe(Result.PRMergeSkipped);
                            });
                          });

                          describe('when merge option is enabled', () => {
                            beforeEach(() => {
                              mockMerge = 'true';
                            });

                            it('merges the PR', async () => {
                              expect(await run()).toBe(Result.PRMerged);
                            });

                            it('aborts if the PR is not open', async () => {
                              mockPr.data.state = 'unknown';
                              expect(await run()).toBe(Result.PRNotOpen);
                            });

                            it('waits 1 second if the PR is not mergeable then retries', async () => {
                              let resolved = false;
                              let error: any;

                              mockPr.data.mergeable = false;
                              const result = run();
                              result
                                .then(() => (resolved = true))
                                .catch((e) => (error = e));
                              await whenAllPromisesFinished();
                              expect(error).toBeUndefined();
                              expect(resolved).toBe(false);

                              mockPr.data.mergeable = true;
                              jest.advanceTimersByTime(999);
                              await whenAllPromisesFinished();
                              expect(resolved).toBe(false);

                              jest.advanceTimersByTime(1);
                              await whenAllPromisesFinished();
                              expect(resolved).toBe(true);

                              expect(await result).toBe(Result.PRMerged);
                            });

                            it('waits 1 second if the PR fails to merge and then retries', async () => {
                              let resolved = false;
                              let error: any;

                              validMergeCallMock.mockImplementationOnce(() => {
                                throw new Error('Oops');
                              });

                              const result = run();
                              result
                                .then(() => (resolved = true))
                                .catch((e) => (error = e));
                              await whenAllPromisesFinished();
                              expect(error).toBeUndefined();
                              expect(resolved).toBe(false);

                              jest.advanceTimersByTime(999);
                              await whenAllPromisesFinished();
                              expect(resolved).toBe(false);

                              jest.advanceTimersByTime(1);
                              await whenAllPromisesFinished();
                              expect(resolved).toBe(true);

                              expect(await result).toBe(Result.PRMerged);
                            });

                            it('stops if the merge fails because the head changed', async () => {
                              validMergeCallMock.mockImplementation(() => {
                                throw { status: 409 };
                              });

                              expect(await run()).toBe(Result.PRHeadChanged);
                            });

                            it('throws when it has retried for 6 hours', async () => {
                              let rejected = false;
                              let error: any;

                              mockPr.data.mergeable = false;
                              const result = run();
                              result.catch((e) => {
                                rejected = true;
                                error = e;
                              });
                              await whenAllPromisesFinished();
                              expect(error).toBeUndefined();
                              expect(rejected).toBe(false);

                              jest.runOnlyPendingTimers();
                              await whenAllPromisesFinished();
                              expect(rejected).toBe(false);

                              jest.setSystemTime(6 * 60 * 60 * 1000);
                              jest.runOnlyPendingTimers();
                              await whenAllPromisesFinished();

                              expect(rejected).toBe(true);
                              expect(error?.message).toBe('Timed out');
                            });
                          });
                        });
                      });
                    }
                  });
                }
              );
            });
          });
        });
      });
    }
  );
});
Example #25
Source File: OcrContribute.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('OcrContribute', () => {
  const resultData = {
    data: [
      {
        dataset_row_id: 1248671,
        media_data: 'inbound/ocr/Hindi/test.png',
      },
      {
        dataset_row_id: 1248672,
        media_data: 'inbound/ocr/Hindi/test2.png',
      },
      {
        dataset_row_id: 1248673,
        media_data: 'inbound/ocr/Hindi/test3.png',
      },
      {
        dataset_row_id: 1248674,
        media_data: 'inbound/ocr/Hindi/test4.png',
      },
      {
        dataset_row_id: 1248675,
        media_data: 'inbound/ocr/Hindi/test5.png',
      },
    ],
  };
  const setup = async (resultData: any) => {
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'Hindi');

    const locationInfo = {
      country: 'Test Country',
      regionName: 'Sample Region',
    };

    when(localStorage.getItem)
      .calledWith('locationInfo')
      .mockImplementation(() => JSON.stringify(locationInfo));

    const speakerDetails = {
      userName: 'abc',
      motherTongue: '',
      age: '',
      gender: '',
      language: 'Hindi',
      toLanguage: '',
    };

    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(() => JSON.stringify(speakerDetails));

    fetchMock.doMockOnceIf('/media/ocr').mockResponseOnce(JSON.stringify(resultData));
    const renderResult = render(<OcrContribute />);

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/media/ocr', {
        body: JSON.stringify({
          language: 'Hindi',
          userName: 'abc',
        }),
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
      });
    });

    await waitFor(() => expect(screen.queryByTestId('PageSpinner')).not.toBeInTheDocument());

    return renderResult;
  };

  it('should render the component and matches it against stored snapshot', async () => {
    const { asFragment } = await setup(resultData);

    expect(asFragment()).toMatchSnapshot();
  });

  it('should show the thank you message when no data present', async () => {
    const result = { data: [] };
    await setup(result);

    await waitFor(() => {
      expect(screen.getByText('ocrContributeNoDataThankYouMessage')).toBeInTheDocument();
    });
  });

  it('should show the error popup when api throw the error and close modal on clicking button', async () => {
    const url = '/media/ocr';
    const errorResponse = new Error('Some error');
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);
    render(<OcrContribute />);
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/media/ocr', {
        body: JSON.stringify({
          language: 'Hindi',
          userName: 'abc',
        }),
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
      });
    });

    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(screen.queryByRole('button', { name: 'close' })).not.toBeInTheDocument();
    });
  });

  it('should show the error popup for 2nd sentence when api throw the error and modal should close on clicking button', async () => {
    const url = '/skip';
    const errorResponse = new Error('Some error');
    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body:
          expect.stringContaining('"userName":"abc"') &&
          expect.stringContaining('"language":"Hindi"') &&
          expect.stringContaining('"sentenceId":"1248671"') &&
          expect.stringContaining('"type":"ocr"'),
      });
    });

    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(screen.queryByText('apiFailureError')).not.toBeInTheDocument();
    });
  });

  it('should test the textarea text with valid language', async () => {
    await setup(resultData);

    userEvent.type(screen.getByRole('textbox', { name: 'addText (hindi)' }), 'बपपप');

    await waitFor(() => {
      expect(screen.queryByText('Please type in your chosen language')).not.toBeInTheDocument();
    });
  });

  it('should expand the  image', async () => {
    await setup(resultData);

    expect(screen.getByTestId('ExpandView')).toBeInTheDocument();
    expect(screen.getByAltText('OCR Data')).toBeInTheDocument();

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

    await waitFor(() => {
      expect(screen.getByTestId('CollapseView')).toBeInTheDocument();
      expect(screen.getByAltText('OCR Data Expanded')).toBeInTheDocument();
    });
  });

  it('should test the cancel button functionality', async () => {
    await setup(resultData);

    expect(screen.getByRole('button', { name: 'cancel' })).toBeDisabled();

    userEvent.type(screen.getByRole('textbox', { name: 'addText (hindi)' }), 'बपपप');

    expect(screen.getByRole('button', { name: 'cancel' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'cancel' }));

    expect(screen.getByRole('button', { name: 'cancel' })).toBeDisabled();

    userEvent.type(screen.getByRole('textbox', { name: 'addText (hindi)' }), 'abc');

    expect(screen.getByRole('button', { name: 'cancel' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'cancel' }));

    expect(screen.getByRole('button', { name: 'cancel' })).toBeDisabled();

    await waitFor(() => {
      expect(screen.getByRole('textbox', { name: 'addText (hindi)' })).toHaveValue('');
    });
  });

  it('should test the skip functionality', async () => {
    const url = '/skip';
    const successResponse = { message: 'Skipped successfully.', statusCode: 200 };

    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockResponseOnce(JSON.stringify(successResponse));

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body:
          expect.stringContaining('"userName":"abc"') &&
          expect.stringContaining('"language":"Hindi"') &&
          expect.stringContaining('"sentenceId":"1248671"') &&
          expect.stringContaining('"type":"ocr"'),
      });
    });
  });

  it('should test the submit button', async () => {
    const url = '/store';
    const successResponse = { success: true };

    await setup(resultData);

    fetchMock.doMockOnceIf(url).mockResponseOnce(JSON.stringify(successResponse));

    expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();

    userEvent.type(screen.getByRole('textbox', { name: 'addText (hindi)' }), 'बपपप');

    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'submit' })).toBeEnabled();
    });

    userEvent.click(screen.getByRole('button', { name: 'submit' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body:
          expect.stringContaining('"userInput":"बपपप"') &&
          expect.stringContaining('"language":"Hindi"') &&
          expect.stringContaining('"sentenceId":"1248671"') &&
          expect.stringContaining('"speakerDetails":{"userName":"abc"}') &&
          expect.stringContaining('"type":"ocr"'),
      });
    });

    await waitFor(() => expect(screen.queryByRole('img', { name: 'check' })).toBeInTheDocument());

    await waitFor(() => expect(screen.queryByRole('img', { name: 'check' })).not.toBeInTheDocument());
  });

  it('should go to thank you page after 5 skip sentences', async () => {
    const url = '/skip';
    const successResponse = { message: 'Skipped successfully.', statusCode: 200 };

    await setup(resultData);
    fetchMock.doMockIf(url).mockResponse(JSON.stringify(successResponse));

    router.push = jest.fn();

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });

    await waitFor(() => {
      expect(router.push).toHaveBeenCalledWith(expect.stringContaining('/thank-you'), undefined, {
        locale: 'en',
      });
    });
  });

  it('should go to thank you page after 5 skip sentences but last sentence throw an error', async () => {
    const url = '/skip';
    const errorResponse = new Error('Some error');
    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body:
          expect.stringContaining('"userName":"abc"') &&
          expect.stringContaining('"language":"Hindi"') &&
          expect.stringContaining('"sentenceId":"1248671"') &&
          expect.stringContaining('"type":"ocr"'),
      });
    });
    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });
  });

  it('should go to thank you page after 4 skip sentences and last sentence throw an error when user submit', async () => {
    const url = '/store';
    const errorResponse = new Error('Some error');
    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });

    expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();

    userEvent.type(screen.getByRole('textbox', { name: 'addText (hindi)' }), 'बपपप');

    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'submit' })).toBeEnabled();
    });

    userEvent.click(screen.getByRole('button', { name: 'submit' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body:
          expect.stringContaining('"userInput":"बपपप"') &&
          expect.stringContaining('"language":"Hindi"') &&
          expect.stringContaining('"sentenceId":"1248671"') &&
          expect.stringContaining('"speakerDetails":{"userName":"abc"}') &&
          expect.stringContaining('"type":"ocr"'),
      });
    });

    await waitFor(() => expect(screen.queryByRole('img', { name: 'check' })).toBeInTheDocument());

    await waitFor(() => expect(screen.queryByRole('img', { name: 'check' })).not.toBeInTheDocument());

    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(router.push).toHaveBeenCalledWith(expect.stringContaining('/thank-you'), undefined, {
        locale: 'en',
      });
    });
  });
});
Example #26
Source File: backup.test.ts    From joplin-plugin-backup with MIT License 4 votes vote down vote up
describe("Backup", function () {
  beforeEach(async () => {
    /* prettier-ignore */
    when(spyOnsSettingsValue)
      .mockImplementation(() => Promise.resolve("no mockImplementation"))
      .calledWith("fileLogLevel").mockImplementation(() => Promise.resolve("error"))
      .calledWith("path").mockImplementation(() => Promise.resolve(testPath.backupBasePath));

    /* prettier-ignore */
    when(spyOnGlobalValue)
      .mockImplementation(() => Promise.resolve("no mockImplementation"))
      .calledWith("profileDir").mockImplementation(() => Promise.resolve(testPath.joplinProfile))
      .calledWith("templateDir").mockImplementation(() => Promise.resolve(testPath.templates));

    await createTestStructure();
    backup = new Backup() as any;
    backup.backupStartTime = new Date();
    backup.backupSetName = "{YYYYMMDDHHmm}";

    spyOnSaveBackupInfo = jest
      .spyOn(backup, "saveBackupInfo")
      .mockImplementation(() => {});

    spyOnLogVerbose = jest
      .spyOn(backup.log, "verbose")
      .mockImplementation(() => {});
    spyOnLogInfo = jest.spyOn(backup.log, "info").mockImplementation(() => {});
    spyOnLogWarn = jest.spyOn(backup.log, "warn").mockImplementation(() => {});
    spyOnLogError = jest
      .spyOn(backup.log, "error")
      .mockImplementation(() => {});
  });

  afterEach(async () => {
    spyOnLogVerbose.mockReset();
    spyOnLogInfo.mockReset();
    spyOnLogWarn.mockReset();
    spyOnLogError.mockReset();
    spyOnsSettingsValue.mockReset();
    spyOnGlobalValue.mockReset();
    spyOnSaveBackupInfo.mockReset();
  });

  afterAll(async () => {
    fs.removeSync(testPath.base);
  });

  describe("Backup path", function () {
    it(`Backup path != Profile`, async () => {
      await backup.loadBackupPath();
      expect(backup.backupBasePath).toBe(testPath.backupBasePath);
      expect(backup.backupBasePath).not.toBe(testPath.joplinProfile);

      /* prettier-ignore */
      when(spyOnsSettingsValue)
      .calledWith("path").mockImplementation(() => Promise.resolve(""));
      await backup.loadBackupPath();
      expect(backup.backupBasePath).not.toBe(testPath.joplinProfile);
      expect(backup.backupBasePath).toBe(null);

      /* prettier-ignore */
      when(spyOnsSettingsValue)
      .calledWith("path").mockImplementation(() => Promise.resolve(testPath.joplinProfile));
      await backup.loadBackupPath();
      expect(backup.backupBasePath).not.toBe(testPath.joplinProfile);
      expect(backup.backupBasePath).toBe(null);

      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);
    });

    it(`relative paths`, async () => {
      const backupPath = "../";
      /* prettier-ignore */
      when(spyOnsSettingsValue)
      .calledWith("path").mockImplementation(() => Promise.resolve(backupPath));
      await backup.loadBackupPath();
      const toBe = path.normalize(
        path.join(testPath.backupBasePath, backupPath)
      );
      expect(backup.backupBasePath).toBe(toBe);
      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);
    });
  });

  describe("Div", function () {
    it(`Create empty folder`, async () => {
      const folder = await backup.createEmptyFolder(
        testPath.backupBasePath,
        "profile"
      );
      const check = path.join(testPath.backupBasePath, "profile");
      expect(folder).toBe(check);
      expect(fs.existsSync(check)).toBe(true);
      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);
    });

    it(`Delete log`, async () => {
      backup.logFile = path.join(testPath.backupBasePath, "test.log");
      fs.writeFileSync(backup.logFile, "data");

      expect(fs.existsSync(backup.logFile)).toBe(true);
      await backup.deleteLogFile();
      expect(fs.existsSync(backup.logFile)).toBe(false);
      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);
    });
  });

  describe("moveFinishedBackup", function () {
    it(`no retention`, async () => {
      const emptyFolder = path.join(testPath.activeBackupJob, "emptyFolder");
      const emptyFolderCheck = path.join(
        testPath.backupBasePath,
        "emptyFolder"
      );
      const folder = path.join(testPath.activeBackupJob, "folder");
      const folderCheck = path.join(testPath.backupBasePath, "folder");
      const file1 = path.join(folder, "file.txt");
      const file1Check = path.join(folderCheck, "file.txt");
      const file2 = path.join(testPath.activeBackupJob, "file.txt");
      const file2Check = path.join(testPath.backupBasePath, "file.txt");
      backup.backupBasePath = testPath.backupBasePath;
      backup.activeBackupPath = testPath.activeBackupJob;

      fs.emptyDirSync(testPath.activeBackupJob);
      fs.emptyDirSync(emptyFolder);
      fs.emptyDirSync(folder);
      fs.writeFileSync(file1, "file");
      fs.writeFileSync(file2, "file");

      backup.backupRetention = 1;

      expect(await backup.moveFinishedBackup()).toBe(testPath.backupBasePath);
      expect(fs.existsSync(folderCheck)).toBe(true);
      expect(fs.existsSync(emptyFolderCheck)).toBe(true);
      expect(fs.existsSync(file1Check)).toBe(true);
      expect(fs.existsSync(file2Check)).toBe(true);
      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);
    });

    it(`retention > 1`, async () => {
      const backupDst = path.join(testPath.backupBasePath, "202101021630");
      const testEpoch = new Date(2021, 0, 2, 16, 30, 45, 0).getTime();
      const spyOnDateNow = jest
        .spyOn(Date, "now")
        .mockImplementation(() => testEpoch);

      const emptyFolder = path.join(testPath.activeBackupJob, "emptyFolder");
      const emptyFolderCheck = path.join(backupDst, "emptyFolder");
      const folder = path.join(testPath.activeBackupJob, "folder");
      const folderCheck = path.join(backupDst, "folder");
      const file1 = path.join(folder, "file.txt");
      const file1Check = path.join(folderCheck, "file.txt");
      const file2 = path.join(testPath.activeBackupJob, "file.txt");
      const file2Check = path.join(backupDst, "file.txt");
      backup.backupBasePath = testPath.backupBasePath;
      backup.activeBackupPath = testPath.activeBackupJob;

      fs.emptyDirSync(testPath.activeBackupJob);
      fs.emptyDirSync(emptyFolder);
      fs.emptyDirSync(folder);
      fs.writeFileSync(file1, "file");
      fs.writeFileSync(file2, "file");

      backup.backupRetention = 2;

      expect(await backup.moveFinishedBackup()).toBe(backupDst);
      expect(fs.existsSync(folderCheck)).toBe(true);
      expect(fs.existsSync(emptyFolderCheck)).toBe(true);
      expect(fs.existsSync(file1Check)).toBe(true);
      expect(fs.existsSync(file2Check)).toBe(true);
      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);

      spyOnDateNow.mockRestore();
    });

    it(`retention > 1, folder exist`, async () => {
      backup.backupBasePath = testPath.backupBasePath;
      backup.activeBackupPath = testPath.activeBackupJob;
      backup.backupSetName = "JoplinBackupSet";
      backup.backupRetention = 2;

      const expected = path.join(
        testPath.backupBasePath,
        backup.backupSetName + " (1)"
      );

      fs.emptyDirSync(testPath.activeBackupJob);
      const existingBackupSet = path.join(
        testPath.backupBasePath,
        backup.backupSetName
      );
      fs.emptyDirSync(existingBackupSet);
      expect(fs.existsSync(existingBackupSet)).toBe(true);

      expect(fs.existsSync(expected)).toBe(false);
      expect(await backup.moveFinishedBackup()).toBe(expected);
      expect(fs.existsSync(expected)).toBe(true);
    });

    it(`retention > 1, file exist`, async () => {
      backup.backupBasePath = testPath.backupBasePath;
      backup.activeBackupPath = testPath.activeBackupJob;
      backup.backupSetName = "JoplinBackupSet";
      backup.backupRetention = 2;

      const zipFile = path.join(testPath.backupBasePath, "test.7z");
      fs.writeFileSync(zipFile, "backup set");
      expect(fs.existsSync(zipFile)).toBe(true);

      const expected = path.join(
        testPath.backupBasePath,
        backup.backupSetName + " (1).7z"
      );

      fs.emptyDirSync(testPath.activeBackupJob);
      const existingBackupSet = path.join(
        testPath.backupBasePath,
        backup.backupSetName + ".7z"
      );
      fs.writeFileSync(existingBackupSet, "backup set");
      expect(fs.existsSync(existingBackupSet)).toBe(true);

      expect(fs.existsSync(expected)).toBe(false);
      expect(await backup.moveFinishedBackup(zipFile)).toBe(expected);
      expect(fs.existsSync(expected)).toBe(true);
    });
  });
  describe("Backup set", function () {
    it(`Name`, async () => {
      const testEpoch = new Date(2021, 0, 2, 16, 30, 45, 0).getTime();
      /* prettier-ignore */
      const spyOnDateNow = jest.spyOn(Date, "now").mockImplementation(() => testEpoch);

      const testCases = [
        {
          backupSetName: "{YYYYMMDDHHmm}",
          expected: "202101021630",
        },
        {
          backupSetName: "{YYYY-MM-DD HH:mm}",
          expected: "2021-01-02 16:30",
        },
        {
          backupSetName: "Joplinbackup_{YYYYMMDDHHmm}",
          expected: "Joplinbackup_202101021630",
        },
        {
          backupSetName: "A {YYYY} b {MMDDHHmm}",
          expected: "A 2021 b 01021630",
        },
        {
          backupSetName: "j{j}j",
          expected: "jjj",
        },
        {
          backupSetName: "No var",
          expected: "No var",
        },
      ];

      for (const testCase of testCases) {
        backup.backupSetName = testCase.backupSetName;
        expect(await backup.getBackupSetFolderName()).toBe(testCase.expected);
      }

      spyOnDateNow.mockRestore();
      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);
    });

    it(`Creation`, async () => {
      const testEpoch = new Date(2021, 0, 2, 16, 30, 45, 0);
      const spyOnDateNow = jest
        .spyOn(Date, "now")
        .mockImplementation(() => testEpoch.getTime());

      const testCases = [
        {
          zipArchive: "no",
          backupRetention: 1,
          password: null,
          singleJex: false,
          result: testPath.backupBasePath,
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "testFile.txt"),
          saveBackupInfoCalled: 0,
        },
        {
          zipArchive: "no",
          backupRetention: 1,
          password: "secret",
          singleJex: false,
          result: testPath.backupBasePath,
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "testFile.txt.7z"),
          saveBackupInfoCalled: 0,
        },
        {
          zipArchive: "no",
          backupRetention: 2,
          password: null,
          singleJex: false,
          result: path.join(testPath.backupBasePath, "202101021630"),
          testFile: "testFile.txt",
          checkFile: path.join(
            testPath.backupBasePath,
            "202101021630",
            "testFile.txt"
          ),
          saveBackupInfoCalled: 1,
        },
        {
          zipArchive: "yes",
          backupRetention: 1,
          password: null,
          singleJex: false,
          result: testPath.backupBasePath,
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "testFile.txt.7z"),
          saveBackupInfoCalled: 0,
        },
        {
          zipArchive: "yes",
          backupRetention: 2,
          password: null,
          singleJex: false,
          result: path.join(testPath.backupBasePath, "202101021630"),
          testFile: "testFile.txt",
          checkFile: path.join(
            testPath.backupBasePath,
            "202101021630",
            "testFile.txt.7z"
          ),
          saveBackupInfoCalled: 1,
        },
        {
          zipArchive: "yesone",
          backupRetention: 1,
          password: null,
          singleJex: false,
          result: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
          saveBackupInfoCalled: 0,
        },
        {
          zipArchive: "yesone",
          backupRetention: 2,
          password: null,
          singleJex: false,
          result: path.join(testPath.backupBasePath, "202101021630.7z"),
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "202101021630.7z"),
          saveBackupInfoCalled: 1,
        },
        {
          zipArchive: "no",
          backupRetention: 1,
          password: null,
          singleJex: true,
          result: testPath.backupBasePath,
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "testFile.txt"),
          saveBackupInfoCalled: 0,
        },
        {
          zipArchive: "no",
          backupRetention: 2,
          password: null,
          singleJex: true,
          result: path.join(testPath.backupBasePath, "202101021630"),
          testFile: "testFile.txt",
          checkFile: path.join(
            testPath.backupBasePath,
            "202101021630",
            "testFile.txt"
          ),
          saveBackupInfoCalled: 1,
        },
        {
          zipArchive: "yes",
          backupRetention: 1,
          password: null,
          singleJex: true,
          result: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
          saveBackupInfoCalled: 0,
        },
        {
          zipArchive: "yes",
          backupRetention: 2,
          password: null,
          singleJex: true,
          result: path.join(testPath.backupBasePath, "202101021630.7z"),
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "202101021630.7z"),
          saveBackupInfoCalled: 1,
        },
        {
          zipArchive: "yesone",
          backupRetention: 1,
          password: null,
          singleJex: true,
          result: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
          saveBackupInfoCalled: 0,
        },
        {
          zipArchive: "yesone",
          backupRetention: 1,
          password: "secret",
          singleJex: true,
          result: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
          saveBackupInfoCalled: 0,
        },
        {
          zipArchive: "yesone",
          backupRetention: 2,
          password: null,
          singleJex: true,
          result: path.join(testPath.backupBasePath, "202101021630.7z"),
          testFile: "testFile.txt",
          checkFile: path.join(testPath.backupBasePath, "202101021630.7z"),
          saveBackupInfoCalled: 1,
        },
      ];

      backup.backupBasePath = testPath.backupBasePath;
      backup.activeBackupPath = testPath.activeBackupJob;
      backup.backupStartTime = testEpoch;
      backup.logFile = path.join(testPath.backupBasePath, "test.log");

      /* prettier-ignore */
      when(spyOnsSettingsValue)
            .calledWith("backupInfo").mockImplementation(() => Promise.resolve(JSON.stringify([])));
      jest.spyOn(backup, "saveBackupInfo").mockImplementation(() => {});

      for (const testCase of testCases) {
        await createTestStructure();
        fs.emptyDirSync(testPath.activeBackupJob);
        const fileName = testCase.testFile;
        const file = path.join(testPath.activeBackupJob, fileName);
        fs.writeFileSync(file, "testFile");
        expect(fs.existsSync(file)).toBe(true);

        backup.zipArchive = testCase.zipArchive;
        backup.backupRetention = testCase.backupRetention;
        backup.singleJex = testCase.singleJex;
        backup.passwordEnabled = testCase.password === null ? false : true;
        backup.password = testCase.password;

        const result = await backup.makeBackupSet();
        expect(result).toBe(testCase.result);
        expect(fs.existsSync(testCase.checkFile)).toBe(true);
        expect(backup.saveBackupInfo).toHaveBeenCalledTimes(
          testCase.saveBackupInfoCalled
        );
        const pwCheck = await sevenZip.passwordProtected(testCase.checkFile);
        if (backup.passwordEnabled === true || testCase.zipArchive !== "no") {
          expect(pwCheck).toBe(backup.passwordEnabled);
        }

        backup.saveBackupInfo.mockReset();
        fs.emptyDirSync(testPath.activeBackupJob);
        expect(fs.existsSync(file)).toBe(false);
      }

      spyOnDateNow.mockRestore();
    });
  });

  describe("Backup retention", function () {
    it(`Backups < retention`, async () => {
      const backupRetention = 3;
      const folder1 = path.join(testPath.backupBasePath, "202101011630");
      const folder2 = path.join(testPath.backupBasePath, "202101021630");

      fs.emptyDirSync(folder1);
      fs.emptyDirSync(folder2);

      const backupInfo = [
        { name: "202101011630", date: 1 },
        { name: "202101021630", date: 2 },
      ];
      /* prettier-ignore */
      when(spyOnsSettingsValue)
            .calledWith("backupInfo").mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));

      backup.deleteOldBackupSets(testPath.backupBasePath, backupRetention);

      const folderAnz = fs
        .readdirSync(testPath.backupBasePath, { withFileTypes: true })
        .filter((dirent) => dirent.isDirectory()).length;

      expect(folderAnz).toBe(2);

      expect(fs.existsSync(folder1)).toBe(true);
      expect(fs.existsSync(folder2)).toBe(true);
    });

    it(`Backups = retention`, async () => {
      const backupRetention = 3;
      const folder1 = path.join(testPath.backupBasePath, "202101011630");
      const folder2 = path.join(testPath.backupBasePath, "202101021630");
      const folder3 = path.join(testPath.backupBasePath, "202101031630");

      fs.emptyDirSync(folder1);
      fs.emptyDirSync(folder2);
      fs.emptyDirSync(folder3);

      const backupInfo = [
        { name: "202101011630", date: 1 },
        { name: "202101021630", date: 2 },
        { name: "202101031630", date: 3 },
      ];
      /* prettier-ignore */
      when(spyOnsSettingsValue)
            .calledWith("backupInfo").mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));

      backup.deleteOldBackupSets(testPath.backupBasePath, backupRetention);
      const folderAnz = fs
        .readdirSync(testPath.backupBasePath, { withFileTypes: true })
        .filter((dirent) => dirent.isDirectory()).length;

      expect(folderAnz).toBe(3);

      expect(fs.existsSync(folder1)).toBe(true);
      expect(fs.existsSync(folder2)).toBe(true);
      expect(fs.existsSync(folder3)).toBe(true);
    });

    it(`Backups > retention`, async () => {
      const backupRetention = 3;
      const folder1 = path.join(testPath.backupBasePath, "202101011630");
      const folder2 = path.join(testPath.backupBasePath, "202101021630");
      const folder3 = path.join(testPath.backupBasePath, "202101031630");
      const folder4 = path.join(testPath.backupBasePath, "202101041630");
      const folder5 = path.join(testPath.backupBasePath, "202101051630");

      fs.emptyDirSync(folder1);
      fs.emptyDirSync(folder2);
      fs.emptyDirSync(folder3);
      fs.emptyDirSync(folder4);
      fs.emptyDirSync(folder5);

      const backupInfo = [
        { name: "202101011630", date: 1 },
        { name: "202101021630", date: 2 },
        { name: "202101031630", date: 3 },
        { name: "202101041630", date: 4 },
        { name: "202101051630", date: 5 },
      ];
      /* prettier-ignore */
      when(spyOnsSettingsValue)
            .calledWith("backupInfo").mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));

      await backup.deleteOldBackupSets(
        testPath.backupBasePath,
        backupRetention
      );

      const folderAnz = fs
        .readdirSync(testPath.backupBasePath, { withFileTypes: true })
        .filter((dirent) => dirent.isDirectory()).length;

      expect(folderAnz).toBe(3);
      expect(fs.existsSync(folder1)).toBe(false);
      expect(fs.existsSync(folder2)).toBe(false);
      expect(fs.existsSync(folder3)).toBe(true);
      expect(fs.existsSync(folder4)).toBe(true);
      expect(fs.existsSync(folder5)).toBe(true);
    });
  });

  describe("Logging", function () {
    beforeEach(async () => {
      backup.setupLog();
    });

    it(`Default`, async () => {
      expect(backup.log.transports.console.level).toBe("verbose");
      expect(backup.log.transports.file.level).toBe(false);
    });

    it(`Toggel file`, async () => {
      await backup.fileLogging(false);
      expect(backup.log.transports.file.level).toBe(false);

      /* prettier-ignore */
      when(spyOnsSettingsValue)
        .calledWith("fileLogLevel").mockImplementation(() => Promise.resolve("verbose"));

      backup.backupBasePath = "./";
      await backup.fileLogging(true);
      expect(backup.log.transports.file.level).toBe("verbose");

      /* prettier-ignore */
      when(spyOnsSettingsValue)
        .calledWith("fileLogLevel").mockImplementation(() => Promise.resolve("error"));

      backup.backupBasePath = "./";
      await backup.fileLogging(true);
      expect(backup.log.transports.file.level).toBe("error");
    });

    it(`move logfile`, async () => {
      const testCases = [
        {
          zipArchive: "no",
          password: null,
          logDst: testPath.backupBasePath,
          testLogFile: path.join(testPath.backupBasePath, "backup.log"),
        },
        {
          zipArchive: "no",
          password: null,
          logDst: path.join(testPath.backupBasePath, "testDir"),
          testLogFile: path.join(
            testPath.backupBasePath,
            "testDir",
            "backup.log"
          ),
        },
        {
          zipArchive: "yes",
          password: null,
          logDst: path.join(testPath.backupBasePath, "testDir"),
          testLogFile: path.join(
            testPath.backupBasePath,
            "testDir",
            "backup.log"
          ),
        },
        {
          zipArchive: "yesone",
          password: null,
          logDst: path.join(testPath.backupBasePath, "Backup.7z"),
          testLogFile: "backup.log",
        },
        {
          zipArchive: "yesone",
          password: "secret",
          logDst: path.join(testPath.backupBasePath, "Backup.7z"),
          testLogFile: "backup.log",
        },
        {
          zipArchive: "no",
          password: "secret",
          logDst: testPath.backupBasePath,
          testLogFile: "backup.log",
        },
      ];

      backup.logFile = path.join(testPath.base, "test.log");
      for (const testCase of testCases) {
        await createTestStructure();
        if (testCase.zipArchive !== "yesone") {
          fs.emptyDirSync(testCase.logDst);
        }
        if (testCase.zipArchive === "yesone") {
          const dummyFile = path.join(testPath.base, "dummy");
          fs.writeFileSync(dummyFile, "dummy");
          await sevenZip.add(testCase.logDst, dummyFile, testCase.password);
          expect(fs.existsSync(dummyFile)).toBe(true);
          expect(fs.existsSync(testCase.logDst)).toBe(true);
        }

        fs.writeFileSync(backup.logFile, "log");

        backup.zipArchive = testCase.zipArchive;
        backup.password = testCase.password;

        expect(fs.existsSync(backup.logFile)).toBe(true);
        expect(await backup.moveLogFile(testCase.logDst)).toBe(true);
        expect(fs.existsSync(backup.logFile)).toBe(false);

        if (testCase.password !== null || testCase.zipArchive === "yesone") {
          const fileList = await sevenZip.list(
            testCase.logDst,
            testCase.password
          );
          expect(fileList.map((f) => f.file)).toContain(testCase.testLogFile);
        } else {
          expect(fs.existsSync(testCase.testLogFile)).toBe(true);
        }
      }
    });
  });

  describe("Backup action", function () {
    it(`File`, async () => {
      const src1 = path.join(testPath.joplinProfile, "settings.json");
      const src2 = path.join(testPath.joplinProfile, "doesNotExist.json");
      const dst = path.join(testPath.backupBasePath, "settings.json");
      fs.writeFileSync(src1, "data");

      expect(await backup.backupFile(src1, dst)).toBe(true);
      expect(fs.existsSync(dst)).toBe(true);

      expect(await backup.backupFile(src2, dst)).toBe(false);

      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);
    });

    it(`Folder`, async () => {
      const file1 = path.join(testPath.templates, "template1.md");
      const file2 = path.join(testPath.templates, "template2.md");

      const doesNotExist = path.join(testPath.base, "doesNotExist");

      const dst = path.join(testPath.backupBasePath, "templates");
      const checkFile1 = path.join(dst, "template1.md");
      const checkFile2 = path.join(dst, "template2.md");

      fs.writeFileSync(file1, "template1");
      fs.writeFileSync(file2, "template2");

      expect(await backup.backupFolder(testPath.templates, dst)).toBe(true);
      expect(fs.existsSync(checkFile1)).toBe(true);
      expect(fs.existsSync(checkFile2)).toBe(true);

      expect(await backup.backupFolder(doesNotExist, dst)).toBe(false);

      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);
    });

    it(`Profile`, async () => {
      const template = path.join(testPath.templates, "template1.md");
      const settings = path.join(testPath.joplinProfile, "settings.json");
      const userstyle = path.join(testPath.joplinProfile, "userstyle.css");
      const userchrome = path.join(testPath.joplinProfile, "userchrome.css");
      const keymap = path.join(testPath.joplinProfile, "keymap-desktop.json");

      fs.writeFileSync(template, "template");
      fs.writeFileSync(settings, "settings");
      fs.writeFileSync(userstyle, "userstyle");
      fs.writeFileSync(userchrome, "userchrome");
      fs.writeFileSync(keymap, "keymap");

      fs.emptyDirSync(testPath.activeBackupJob);

      const backupTemplate = path.join(
        testPath.activeBackupJob,
        "profile",
        "templates",
        "template1.md"
      );
      const backupSettings = path.join(
        testPath.activeBackupJob,
        "profile",
        "settings.json"
      );
      const backupUserstyle = path.join(
        testPath.activeBackupJob,
        "profile",
        "userstyle.css"
      );
      const backupUserchrome = path.join(
        testPath.activeBackupJob,
        "profile",
        "userchrome.css"
      );
      const backupKeymap = path.join(
        testPath.activeBackupJob,
        "profile",
        "keymap-desktop.json"
      );

      backup.activeBackupPath = testPath.activeBackupJob;
      await backup.backupProfileData();

      expect(fs.existsSync(backupTemplate)).toBe(true);
      expect(fs.existsSync(backupSettings)).toBe(true);
      expect(fs.existsSync(backupUserstyle)).toBe(true);
      expect(fs.existsSync(backupUserchrome)).toBe(true);
      expect(fs.existsSync(backupKeymap)).toBe(true);

      expect(backup.log.error).toHaveBeenCalledTimes(0);
      expect(backup.log.warn).toHaveBeenCalledTimes(0);
    });
  });
});
Example #27
Source File: AsrDashboard.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('AsrDashboard', () => {
  global.document.getElementById = jest.fn().mockImplementation(
    x =>
      x === 'float' && {
        style: {
          width: '50%',
        },
      }
  );

  const setup = async () => {
    fetchMock.doMockIf('/aggregated-json/cumulativeDataByLanguage.json').mockResponse(
      JSON.stringify([
        {
          language: 'English',
          total_contribution_count: 36,
          total_contributions: 0.057,
          total_speakers: 9,
          total_validation_count: 2,
          total_validations: 0.001,
          type: 'text',
        },
      ])
    );
    const renderResult = render(
      <SWRConfig value={{ provider: () => new Map() }}>
        <AsrDashboard />
      </SWRConfig>
    );
    await screen.findByText('ContributionStats');
    return renderResult;
  };

  it('should contain language selector', async () => {
    await setup();
    expect(screen.getByRole('combobox', { name: 'Select Language' })).toBeInTheDocument();
  });

  it('changing language from language selector should update stats', async () => {
    await setup();
    expect(screen.getByRole('combobox', { name: 'Select Language' })).toBeInTheDocument();
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'English');
    await waitForElementToBeRemoved(() => screen.queryAllByTestId('Loader'));
    expect(fetchMock).toBeCalledWith('/aggregated-json/cumulativeDataByLanguage.json');
    expect(screen.queryByText('languages')).not.toBeInTheDocument();
  });

  it('changing language from language selector should display nodata message when data not available', async () => {
    await setup();
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'English');
    await waitForElementToBeRemoved(() => screen.queryAllByTestId('Loader'));
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'Bengali');
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/aggregated-json/cumulativeDataByLanguage.json');
    });
    await waitFor(() => {
      expect(screen.getByText('noDataMessageDashboard')).toBeInTheDocument();
    });
    await waitFor(() => expect(screen.queryByText('noDataMessageDashboard')).not.toBeInTheDocument());
    expect(screen.queryByText('languages')).not.toBeInTheDocument();
  });

  it('changing to language where data not available and clicking contribute now should display change user modal for new user', async () => {
    await setup();
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'Bengali');
    await waitFor(() => {
      expect(screen.getByText('noDataMessageDashboard')).toBeInTheDocument();
    });
    userEvent.click(screen.getByRole('button', { name: 'contributeNow' }));
    await waitFor(() => expect(screen.getByTestId('ChangeUserForm')).toBeInTheDocument());

    userEvent.click(screen.getByRole('button', { name: 'Close' }));

    await waitForElementToBeRemoved(() => screen.queryByTestId('ChangeUserModal'));
  });

  it('changing to language where data not available and clicking contribute now should redirect for existing user', async () => {
    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(
        () => '{"userName":"abc","motherTongue":"","age":"","gender":"","language":"English","toLanguage":""}'
      );
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'English');
    await setup();
    await waitFor(() => {
      expect(localStorage.getItem).toBeCalled();
    });
    userEvent.selectOptions(screen.getByRole('combobox', { name: 'Select Language' }), 'Bengali');
    await waitFor(() => {
      expect(screen.getByText('noDataMessageDashboard')).toBeInTheDocument();
    });
    userEvent.click(screen.getByRole('button', { name: 'contributeNow' }));
    await waitFor(() => expect(screen.queryByTestId('ChangeUserModal')).not.toBeInTheDocument());
  });
});
Example #28
Source File: AsrSpeak.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('AsrSpeak', () => {
  const resultData = {
    data: [
      {
        dataset_row_id: 371765,
        media_data: 'बल्कि मजबूरी थी 20',
        source_info: null,
      },
      {
        dataset_row_id: 371766,
        media_data: 'बल्कि मजबूरी थी 21',
        source_info: null,
      },
      {
        dataset_row_id: 371767,
        media_data: 'बल्कि मजबूरी थी 22',
        source_info: null,
      },
      {
        dataset_row_id: 371768,
        media_data: 'बल्कि मजबूरी थी 23',
        source_info: null,
      },
      {
        dataset_row_id: 371769,
        media_data: 'बल्कि मजबूरी थी 24',
        source_info: null,
      },
    ],
  };
  const setup = async (resultData: any) => {
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'Hindi');

    const locationInfo = {
      country: 'India',
      regionName: 'National Capital Territory of Delhi',
    };

    when(localStorage.getItem)
      .calledWith('locationInfo')
      .mockImplementation(() => JSON.stringify(locationInfo));

    const speakerDetails = {
      userName: 'abc',
      motherTongue: '',
      age: '',
      gender: '',
      language: 'Hindi',
      toLanguage: '',
    };

    const lastSpeakerDetails = {
      userName: 'abc1',
      motherTongue: '',
      age: '',
      gender: '',
      language: 'Hindi',
      toLanguage: '',
    };

    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(() => JSON.stringify(speakerDetails));

    when(localStorage.getItem)
      .calledWith('lastSpeakerDetails')
      .mockImplementation(() => JSON.stringify(lastSpeakerDetails));

    fetchMock.doMockOnceIf('/media/text').mockResponseOnce(JSON.stringify(resultData));
    const renderResult = render(<AsrSpeak />);

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith('/media/text', {
        body: JSON.stringify({
          language: 'Hindi',
          userName: 'abc',
        }),
        headers: { 'Content-Type': 'application/json' },
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
      });
    });

    return renderResult;
  };

  it('should start the recording', async () => {
    await setup(resultData);

    expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'startRecording' })).toBeEnabled();
    userEvent.click(screen.getByRole('button', { name: 'startRecording' }));
    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'stopRecording' })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    });
    userEvent.click(screen.getByRole('button', { name: 'stopRecording' }));
  });

  it('should hide the quick tipe bar when user click on tips button', async () => {
    await setup(resultData);

    userEvent.click(screen.getByRole('button', { name: 'tipsIconAlt tips' }));

    await waitFor(() => {
      expect(screen.queryByTestId('QuickTips')).not.toBeInTheDocument();
    });
  });

  it('should close the quick tips when user click on cross button', async () => {
    await setup(resultData);

    userEvent.click(screen.getByRole('button', { name: 'Close' }));

    expect(screen.queryByTestId('QuickTips')).not.toBeInTheDocument();
  });

  it('should show the thank you message when no data present', async () => {
    const result = { data: [] };
    await setup(result);

    await waitFor(() => {
      expect(screen.getByText('asrContributeNoDataThankYouMessage')).toBeInTheDocument();
    });
  });

  it('stop button should stop the audio recording', async () => {
    await setup(resultData);

    expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'startRecording' })).toBeEnabled();
    userEvent.click(screen.getByRole('button', { name: 'startRecording' }));

    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'stopRecording' })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    });

    userEvent.click(screen.getByRole('button', { name: 'stopRecording' }));

    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'reRecord' })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    });
  });

  it('re-record button should start recording the audio again', async () => {
    await setup(resultData);

    expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'startRecording' })).toBeEnabled();
    userEvent.click(screen.getByRole('button', { name: 'startRecording' }));

    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'stopRecording' })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    });

    userEvent.click(screen.getByRole('button', { name: 'stopRecording' }));

    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'reRecord' })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    });

    userEvent.click(screen.getByRole('button', { name: 'reRecord' }));

    await waitFor(() => {
      expect(screen.getByRole('button', { name: 'stopRecording' })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: 'submit' })).toBeDisabled();
    });
  });

  it('should test the skip functionality', async () => {
    const url = '/skip';
    const successResponse = { message: 'Skipped successfully.', statusCode: 200 };

    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockResponseOnce(JSON.stringify(successResponse));

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          language: 'Hindi',
          sentenceId: 371765,
          state_region: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'text',
        }),
      });
    });
  });

  it('should show the error popup when api throw the error and close modal on clicking button', async () => {
    const url = '/skip';
    const errorResponse = new Error('Some error');
    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);
    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          language: 'Hindi',
          sentenceId: 371765,
          state_region: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'text',
        }),
      });
    });
    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(screen.queryByText('apiFailureError')).not.toBeInTheDocument();
    });
  });

  it('should show the error popup for 2nd sentence when api throw the error and modal should close on clicking button', async () => {
    const url = '/skip';
    const errorResponse = new Error('Some error');
    await setup(resultData);
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          language: 'Hindi',
          sentenceId: 371765,
          state_region: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'text',
        }),
      });
    });

    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(screen.queryByText('apiFailureError')).not.toBeInTheDocument();
    });
  });

  it('should go to thank you page after 5 skip sentences', async () => {
    const url = '/skip';
    const successResponse = { message: 'Skipped successfully.', statusCode: 200 };

    await setup(resultData);
    fetchMock.doMockIf(url).mockResponse(JSON.stringify(successResponse));

    router.push = jest.fn();

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });

    await waitFor(() => {
      expect(router.push).toHaveBeenCalledWith(expect.stringContaining('/thank-you'), undefined, {
        locale: 'en',
      });
    });
  });
});
Example #29
Source File: AsrValidate.test.tsx    From crowdsource-dataplatform with MIT License 4 votes vote down vote up
describe('AsrValidate', () => {
  const storeUrl = '/store';
  const skipUrl = '/skip';
  const acceptUrl = '/validate/1717503/accept';
  const rejectUrl = '/validate/1717503/reject';
  const successResponse = { success: true };
  const locationInfo = {
    country: 'India',
    regionName: 'National Capital Territory of Delhi',
  };

  const speakerDetails = {
    userName: 'abc',
    motherTongue: '',
    age: '',
    gender: '',
    language: 'Hindi',
    toLanguage: '',
  };

  const contributionsData = JSON.stringify({
    data: [
      {
        contribution_id: 1717503,
        dataset_row_id: 1248712,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-202131192011.wav',
        contribution: 'सोल को अगर आप नहीं देख सकते शीशा लगा करके आप जरूर देखिए',
        source_info: null,
      },
      {
        contribution_id: 1717502,
        dataset_row_id: 1248711,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-202121195940.wav',
        contribution: 'नहीं देख सकते शीशा लगा करके आप जरूर देखिए',
        source_info: null,
      },
      {
        contribution_id: 1717501,
        dataset_row_id: 1248710,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-202112711182.wav',
        contribution: 'आप जरूर देखिए',
        source_info: null,
      },
      {
        contribution_id: 1717497,
        dataset_row_id: 1248705,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-202083094241.wav',
        contribution: 'देखिए',
        source_info: null,
      },
      {
        contribution_id: 1717496,
        dataset_row_id: 1248704,
        sentence:
          'inbound/asr/English/newsonair.nic.in_09-08-2021_03-37/37_Regional-Shillong-English-0830-20208293814.wav',
        contribution: 'देखिए',
        source_info: null,
      },
    ],
  });

  const setup = async (contributionsData: any) => {
    when(localStorage.getItem)
      .calledWith('contributionLanguage')
      .mockImplementation(() => 'Hindi');

    when(localStorage.getItem)
      .calledWith('locationInfo')
      .mockImplementation(() => JSON.stringify(locationInfo));

    when(localStorage.getItem)
      .calledWith('speakerDetails')
      .mockImplementation(() => JSON.stringify(speakerDetails));

    fetchMock
      .doMockOnceIf('/contributions/text?from=Hindi&to=&username=abc')
      .mockResponseOnce(contributionsData);
    fetchMock.doMockIf(storeUrl).mockResponse(JSON.stringify(successResponse));
    fetchMock.doMockIf(skipUrl).mockResponse(JSON.stringify(successResponse));
    fetchMock.doMockIf(acceptUrl).mockResponse(JSON.stringify(successResponse));
    fetchMock.doMockIf(rejectUrl).mockResponse(JSON.stringify(successResponse));
    const renderResult = render(
      <SWRConfig value={{ provider: () => new Map() }}>
        <AsrValidate />
      </SWRConfig>
    );

    await waitForElementToBeRemoved(() => screen.queryAllByTestId('Loader'));

    return renderResult;
  };

  it('incorrect and correct button should be disabled initially', async () => {
    await setup(contributionsData);

    expect(screen.getByRole('button', { name: 'InCorrect Icon incorrect' })).toBeDisabled();
    expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeDisabled();
  });

  it('play button and skip button should be enabled initially', async () => {
    await setup(contributionsData);

    expect(screen.getByRole('button', { name: 'Play Icon play' })).toBeEnabled();
    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();
  });

  it('should show the thank you message when no data present', async () => {
    const result = JSON.stringify({ data: [] });
    await setup(result);

    await waitFor(() => {
      expect(screen.getByText('asrValidateNoDataThankYouMessage')).toBeInTheDocument();
    });
  });

  it('play button click should play audio and pause button should be enabled', async () => {
    await setup(contributionsData);

    expect(screen.getByRole('img', { name: 'Play Icon' })).toBeInTheDocument();

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument();
  });

  it('pause button click should pause audio and play button should be enabled', async () => {
    await setup(contributionsData);

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument();

    userEvent.click(screen.getByRole('img', { name: 'Pause Icon' }));

    expect(screen.getByRole('img', { name: 'Play Icon' })).toBeInTheDocument();
  });

  it('should enable incorrect and correct button when full audio is played', async () => {
    await setup(contributionsData);

    await waitFor(() =>
      expect(screen.getByRole('button', { name: 'InCorrect Icon incorrect' })).toBeDisabled()
    );
    await waitFor(() => expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeDisabled());

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() =>
      screen.getByTestId('asrValidateAudioElement').dispatchEvent(new window.Event('ended'))
    );
    await waitFor(() => expect(screen.getByRole('img', { name: 'Replay Icon' })).toBeInTheDocument());
    await waitFor(() =>
      expect(screen.getByRole('button', { name: 'InCorrect Icon incorrect' })).toBeEnabled()
    );
    await waitFor(() => expect(screen.getByRole('button', { name: 'Correct Icon correct' })).toBeEnabled());
  });

  it('should replay full audio is played and replay clicked', async () => {
    await setup(contributionsData);

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() =>
      screen.getByTestId('asrValidateAudioElement').dispatchEvent(new window.Event('ended'))
    );
    await waitFor(() => expect(screen.getByRole('img', { name: 'Replay Icon' })).toBeInTheDocument());
    userEvent.click(screen.getByRole('img', { name: 'Replay Icon' }));
    await waitFor(() => expect(screen.getByRole('img', { name: 'Pause Icon' })).toBeInTheDocument());
  });

  it('should test the skip functionality', async () => {
    const url = '/validate/1717503/skip';
    const successResponse = { message: 'Skipped successfully.', statusCode: 200 };

    await setup(contributionsData);
    fetchMock.doMockOnceIf(url).mockResponseOnce(JSON.stringify(successResponse));

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'text',
        }),
      });
    });
  });

  it('should test the correct functionality', async () => {
    const url = '/validate/1717503/accept';
    const successResponse = { message: 'Validate successfully.', statusCode: 200 };

    await setup(contributionsData);

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() =>
      screen.getByTestId('asrValidateAudioElement').dispatchEvent(new window.Event('ended'))
    );

    fetchMock.doMockOnceIf(url).mockResponseOnce(JSON.stringify(successResponse));

    expect(screen.getByRole('img', { name: 'Correct Icon' })).toBeEnabled();

    userEvent.click(screen.getByRole('img', { name: 'Correct Icon' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'text',
        }),
      });
    });
  });

  it('should show the error popup when api throw the error and close modal on clicking button', async () => {
    const url = '/validate/1717503/accept';
    const errorResponse = new Error('Some error');
    await setup(contributionsData);
    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() =>
      screen.getByTestId('asrValidateAudioElement').dispatchEvent(new window.Event('ended'))
    );
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);
    expect(screen.getByRole('img', { name: 'Correct Icon' })).toBeEnabled();

    userEvent.click(screen.getByRole('img', { name: 'Correct Icon' }));
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'text',
        }),
      });
    });
    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(screen.queryByText('apiFailureError')).not.toBeInTheDocument();
    });
  });

  it('should show the error popup for 2nd sentence when api throw the error and modal should close on clicking button', async () => {
    const url = '/validate/1717503/skip';
    const errorResponse = new Error('Some error');
    await setup(contributionsData);
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    userEvent.click(screen.getByRole('button', { name: 'skip' }));
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'text',
        }),
      });
    });
    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });

    await waitFor(() => {
      expect(screen.queryByText('apiFailureError')).not.toBeInTheDocument();
    });
  });

  it('should test the incorrect functionality', async () => {
    const url = '/validate/1717503/reject';
    const successResponse = { message: 'Validate successfully.', statusCode: 200 };

    await setup(contributionsData);

    userEvent.click(screen.getByRole('img', { name: 'Play Icon' }));

    await waitFor(() =>
      screen.getByTestId('asrValidateAudioElement').dispatchEvent(new window.Event('ended'))
    );

    fetchMock.doMockOnceIf(url).mockResponseOnce(JSON.stringify(successResponse));

    expect(screen.getByRole('img', { name: 'InCorrect Icon' })).toBeEnabled();

    userEvent.click(screen.getByRole('img', { name: 'InCorrect Icon' }));

    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          country: 'India',
          state: 'National Capital Territory of Delhi',
          userName: 'abc',
          type: 'text',
        }),
      });
    });
  });

  it('should go to thank you page after 5 skip sentences', async () => {
    const url = '/validate/1717503/skip';
    const errorResponse = new Error('Some error');
    await setup(contributionsData);
    fetchMock.doMockOnceIf(url).mockRejectOnce(errorResponse);

    expect(screen.getByRole('button', { name: 'skip' })).toBeEnabled();

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'skip' }));
    });
    await waitFor(() => {
      expect(fetchMock).toBeCalledWith(url, {
        method: 'POST',
        credentials: 'include',
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          device: 'android 11',
          browser: 'Chrome 13',
          userName: 'abc',
          fromLanguage: 'Hindi',
          sentenceId: 1248712,
          state: 'National Capital Territory of Delhi',
          country: 'India',
          type: 'text',
        }),
      });
    });
    await waitFor(() => {
      expect(screen.getByText('apiFailureError')).toBeInTheDocument();
    });

    await waitFor(() => {
      userEvent.click(screen.getByRole('button', { name: 'close' }));
    });
  });
});