addons/isl/src/__tests__/ChangedFilesWithFetching.test.tsxblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import type {ChangedFile, ChangedFileStatus, RepoRelativePath} from '../types';
b69ab319
b69ab3110import {act, fireEvent, render, screen, waitFor} from '@testing-library/react';
b69ab3111import {nextTick} from 'shared/testUtils';
b69ab3112import App from '../App';
b69ab3113import {__TEST__} from '../ChangedFilesWithFetching';
b69ab3114import {CommitInfoTestUtils, ignoreRTL} from '../testQueries';
b69ab3115import {
b69ab3116 COMMIT,
b69ab3117 expectMessageNOTSentToServer,
b69ab3118 expectMessageSentToServer,
b69ab3119 resetTestMessages,
b69ab3120 simulateCommits,
b69ab3121 simulateMessageFromServer,
b69ab3122 simulateRepoConnected,
b69ab3123} from '../testUtils';
b69ab3124import {leftPad} from '../utils';
b69ab3125
b69ab3126function makeFiles(n: number): Array<RepoRelativePath> {
b69ab3127 return new Array(n).fill(null).map((_, i) => `file${leftPad(i, 3, '0')}.txt`);
b69ab3128}
b69ab3129function withStatus(files: Array<RepoRelativePath>, status: ChangedFileStatus): Array<ChangedFile> {
b69ab3130 return files.map(path => ({path, status}));
b69ab3131}
b69ab3132
b69ab3133describe('ChangedFilesWithFetching', () => {
b69ab3134 beforeEach(() => {
b69ab3135 resetTestMessages();
b69ab3136 render(<App />);
b69ab3137 act(() => {
b69ab3138 simulateRepoConnected();
b69ab3139 expectMessageSentToServer({
b69ab3140 type: 'subscribe',
b69ab3141 kind: 'smartlogCommits',
b69ab3142 subscriptionID: expect.anything(),
b69ab3143 });
b69ab3144 simulateCommits({
b69ab3145 value: [
b69ab3146 COMMIT('1', 'some public base', '0', {phase: 'public', isDot: true}),
b69ab3147 COMMIT('a', 'My Commit', '1', {
b69ab3148 totalFileCount: 2,
b69ab3149 filePathsSample: ['file1.js', 'file2.js'],
b69ab3150 }),
b69ab3151 COMMIT('b', 'Another Commit', 'a', {
b69ab3152 totalFileCount: 700,
b69ab3153 filePathsSample: makeFiles(500),
b69ab3154 }),
b69ab3155 COMMIT('c', 'Another Commit 2', 'a', {
b69ab3156 totalFileCount: 700,
b69ab3157 filePathsSample: makeFiles(500),
b69ab3158 }),
b69ab3159 ],
b69ab3160 });
b69ab3161 });
b69ab3162 });
b69ab3163
b69ab3164 afterEach(() => {
b69ab3165 // reset cache between tests
b69ab3166 __TEST__.commitFilesCache.clear();
b69ab3167 });
b69ab3168
b69ab3169 async function waitForNextPageToLoad() {
b69ab3170 await waitFor(() => {
b69ab3171 expect(screen.getByTestId('changed-files-next-page')).toBeInTheDocument();
b69ab3172 });
b69ab3173 }
b69ab3174
b69ab3175 it("Does not fetch files if they're already all fetched", () => {
b69ab3176 CommitInfoTestUtils.clickToSelectCommit('a');
b69ab3177
b69ab3178 expectMessageNOTSentToServer({
b69ab3179 type: 'fetchCommitChangedFiles',
b69ab3180 hash: 'a',
b69ab3181 limit: expect.anything(),
b69ab3182 });
b69ab3183 });
b69ab3184
b69ab3185 it('Fetches files and shows additional pages', async () => {
b69ab3186 CommitInfoTestUtils.clickToSelectCommit('b');
b69ab3187
b69ab3188 expectMessageSentToServer({type: 'fetchCommitChangedFiles', hash: 'b', limit: undefined});
b69ab3189 act(() => {
b69ab3190 simulateMessageFromServer({
b69ab3191 type: 'fetchedCommitChangedFiles',
b69ab3192 hash: 'b',
b69ab3193 result: {value: {filesSample: withStatus(makeFiles(510), 'M'), totalFileCount: 510}},
b69ab3194 });
b69ab3195 });
b69ab3196
b69ab3197 await waitForNextPageToLoad();
b69ab3198
b69ab3199 expect(screen.getByText(ignoreRTL('file000.txt'))).toBeInTheDocument();
b69ab31100 expect(screen.getByText(ignoreRTL('file499.txt'))).toBeInTheDocument();
b69ab31101 expect(screen.queryByText(ignoreRTL('file500.txt'))).not.toBeInTheDocument();
b69ab31102 fireEvent.click(screen.getByTestId('changed-files-next-page'));
b69ab31103 expect(screen.queryByText(ignoreRTL('file499.txt'))).not.toBeInTheDocument();
b69ab31104 expect(screen.getByText(ignoreRTL('file500.txt'))).toBeInTheDocument();
b69ab31105 expect(screen.getByText(ignoreRTL('file509.txt'))).toBeInTheDocument();
b69ab31106 });
b69ab31107
b69ab31108 it('Caches files', () => {
b69ab31109 CommitInfoTestUtils.clickToSelectCommit('c');
b69ab31110 CommitInfoTestUtils.clickToSelectCommit('a');
b69ab31111 resetTestMessages();
b69ab31112
b69ab31113 CommitInfoTestUtils.clickToSelectCommit('c');
b69ab31114 expectMessageNOTSentToServer({type: 'fetchCommitChangedFiles', hash: expect.anything()});
b69ab31115 });
b69ab31116
b69ab31117 it('Handles race condition when switching commits and responses come in wrong order', async () => {
b69ab31118 // Select commit 'b' - this will start fetching files
b69ab31119 CommitInfoTestUtils.clickToSelectCommit('b');
b69ab31120 expectMessageSentToServer({type: 'fetchCommitChangedFiles', hash: 'b', limit: undefined});
b69ab31121
b69ab31122 // Before 'b' response comes back, switch to commit 'c'
b69ab31123 CommitInfoTestUtils.clickToSelectCommit('c');
b69ab31124 expectMessageSentToServer({type: 'fetchCommitChangedFiles', hash: 'c', limit: undefined});
b69ab31125
b69ab31126 // Simulate 'c' response coming back first (fast)
b69ab31127 act(() => {
b69ab31128 simulateMessageFromServer({
b69ab31129 type: 'fetchedCommitChangedFiles',
b69ab31130 hash: 'c',
b69ab31131 result: {
b69ab31132 value: {
b69ab31133 filesSample: withStatus(['fileC1.txt', 'fileC2.txt', 'fileC3.txt'], 'M'),
b69ab31134 totalFileCount: 3,
b69ab31135 },
b69ab31136 },
b69ab31137 });
b69ab31138 });
b69ab31139
b69ab31140 // Verify we're showing commit 'c' files
b69ab31141 await waitFor(() => {
b69ab31142 expect(screen.getByText(ignoreRTL('fileC1.txt'))).toBeInTheDocument();
b69ab31143 expect(screen.getByText(ignoreRTL('fileC2.txt'))).toBeInTheDocument();
b69ab31144 });
b69ab31145
b69ab31146 // Now simulate 'b' response coming back late (slow)
b69ab31147 act(() => {
b69ab31148 simulateMessageFromServer({
b69ab31149 type: 'fetchedCommitChangedFiles',
b69ab31150 hash: 'b',
b69ab31151 result: {
b69ab31152 value: {
b69ab31153 filesSample: withStatus(['fileB1.txt', 'fileB2.txt', 'fileB3.txt'], 'M'),
b69ab31154 totalFileCount: 3,
b69ab31155 },
b69ab31156 },
b69ab31157 });
b69ab31158 });
b69ab31159
b69ab31160 // Wait a bit to ensure any state updates have completed
b69ab31161 await nextTick();
b69ab31162
b69ab31163 await waitFor(() => {
b69ab31164 // The files should STILL be from commit 'c', not 'b'
b69ab31165 // With the fix enabled, the cancellation token prevents 'b' from overwriting 'c'
b69ab31166 expect(screen.getByText(ignoreRTL('fileC1.txt'))).toBeInTheDocument();
b69ab31167 expect(screen.getByText(ignoreRTL('fileC2.txt'))).toBeInTheDocument();
b69ab31168 });
b69ab31169
b69ab31170 // Verify we're NOT showing commit 'b' files
b69ab31171 expect(screen.queryByText(ignoreRTL('fileB1.txt'))).not.toBeInTheDocument();
b69ab31172 expect(screen.queryByText(ignoreRTL('fileB2.txt'))).not.toBeInTheDocument();
b69ab31173 });
b69ab31174});