From 12f1c4d667061aaf435159c12b01e5efe7144c6d Mon Sep 17 00:00:00 2001 From: Viet Anh Date: Fri, 27 Aug 2021 00:18:42 +0700 Subject: [PATCH 1/6] fix under review tab pagination bug: fetch 5 proposals per request till the end page --- .../Actions/UnvettedActionsProvider.jsx | 4 +- src/hooks/api/useProposalsBatch.js | 105 +++++++++++++++--- teste2e/cypress/e2e/records/recordsList.js | 17 ++- 3 files changed, 100 insertions(+), 26 deletions(-) diff --git a/src/containers/Proposal/Actions/UnvettedActionsProvider.jsx b/src/containers/Proposal/Actions/UnvettedActionsProvider.jsx index 661058e91..7ab4343d9 100644 --- a/src/containers/Proposal/Actions/UnvettedActionsProvider.jsx +++ b/src/containers/Proposal/Actions/UnvettedActionsProvider.jsx @@ -52,8 +52,8 @@ const UnvettedActionsProvider = ({ children, history }) => { successTitle: "Proposal approved", successMessage: ( - The proposal has been successfully approved! Now it will appear under{" "} - In discussion tab among Public + The proposal has been successfully approved! Now it will appear in{" "} + Under review tab among Public Proposals. ), diff --git a/src/hooks/api/useProposalsBatch.js b/src/hooks/api/useProposalsBatch.js index 9a3573d52..17daa650d 100644 --- a/src/hooks/api/useProposalsBatch.js +++ b/src/hooks/api/useProposalsBatch.js @@ -96,7 +96,7 @@ export default function useProposalsBatch({ }) { const [remainingTokens, setRemainingTokens] = useState([]); const [voteStatuses, setStatuses] = useState(statuses); - const [previousPage, setPreviousPage] = useState(0); + const [initializedInventory, setInitializedInventory] = useState(false); const isByRecordStatus = isUndefined(voteStatuses); const proposals = useSelector(sel.proposalsByToken); const recordState = unvetted @@ -116,7 +116,9 @@ export default function useProposalsBatch({ isByRecordStatus ? sel.allByRecordStatus : sel.allByVoteStatus ); const tokens = useMemo( - () => allByStatus[getProposalStatusLabel(currentStatus, isByRecordStatus)], + () => + allByStatus[getProposalStatusLabel(currentStatus, isByRecordStatus)] || + [], [allByStatus, isByRecordStatus, currentStatus] ); const page = useMemo(() => { @@ -130,12 +132,66 @@ export default function useProposalsBatch({ const onFetchProposalsBatch = useAction(act.onFetchProposalsBatch); const onFetchTokenInventory = useAction(act.onFetchTokenInventory); const hasRemainingTokens = !isEmpty(remainingTokens); + + const scanNextStatusTokens = (index, oldTokens) => { + if (index < currentStatuses.length) { + const status = currentStatuses[index]; + const newTokens = getUnfetchedTokens( + proposals, + uniq( + allByStatus[getProposalStatusLabel(status, isByRecordStatus)] || [] + ) + ); + const tokens = [...oldTokens, ...newTokens]; + if (tokens.length < proposalPageSize) { + // scan the next status. + return scanNextStatusTokens(index + 1, tokens); + } + return { + index, + tokens + }; + } + return { index, tokens: [] }; + }; + const [state, send] = useFetchMachine({ actions: { initial: () => send(START), start: () => { - if (hasRemainingTokens) return send(VERIFY); - if (page && page === previousPage) return send(RESOLVE); + // If remaining tokens length is greater than proposal page size. + // Fetch proposals. + if (remainingTokens.length >= proposalPageSize) return send(VERIFY); + + // If remaining tokens length is smaller than proposal page size. + // Find more tokens from inventory or scan from the next status + + // Condition to scan: inventory is initialized and + // the tokens are able to be fetched from the next page + const currentStatusTokens = + allByStatus[ + getProposalStatusLabel(currentStatus, isByRecordStatus) + ] || []; + if ( + initializedInventory && + !( + currentStatusTokens.length % INVENTORY_PAGE_SIZE === 0 && + currentStatusTokens.length > 0 + ) + ) { + const { index, tokens } = scanNextStatusTokens( + statusIndex + 1, + remainingTokens + ); + setStatusIndex(index); + setRemainingTokens(tokens); + if (isEmpty(tokens)) return send(RESOLVE); + + return send(VERIFY); + } + + // Fetch tokens from inventory. Fetch all statuses at the first page. + // Next times, fetch the next page of the current status. onFetchTokenInventory( recordState, page && currentStatus, // first page fetches all status @@ -144,17 +200,23 @@ export default function useProposalsBatch({ ) .catch((e) => send(REJECT, e)) .then(({ votes, records }) => { - setPreviousPage(page); + setInitializedInventory(true); // prepare token batch to fetch proposal for given status const proposalStatusLabel = getProposalStatusLabel( currentStatus, isByRecordStatus ); - const tokens = (isByRecordStatus ? records : votes)[ + const newTokens = (isByRecordStatus ? records : votes)[ proposalStatusLabel ]; - if (!tokens) return send(RESOLVE); + const tokens = [...newTokens, ...remainingTokens]; setRemainingTokens(tokens); + if ( + tokens.length < proposalPageSize && + statusIndex + 1 < currentStatuses.length + ) + return send(RESOLVE); + return send(VERIFY); }); return send(FETCH); @@ -198,21 +260,24 @@ export default function useProposalsBatch({ return send(FETCH); }, done: () => { - // If there are not remaining tokens, check if have unscanned status. - // If yes, change the index to the new status and set up new tokens - if (!hasRemainingTokens && statusIndex + 1 < currentStatuses.length) { - const newIndex = statusIndex + 1; - const newStatus = currentStatuses[newIndex]; - const unfetchedTokens = getUnfetchedTokens( + // If the remaining tokens is smaller than proposal page size and have not scanned status. + // Check the new status and set up new tokens + if ( + remainingTokens.length < proposalPageSize && + statusIndex + 1 < currentStatuses.length + ) { + const nextIndex = statusIndex + 1; + const nextStatus = currentStatuses[nextIndex]; + const nextStatusTokens = getUnfetchedTokens( proposals, uniq( allByStatus[ - getProposalStatusLabel(newStatus, isByRecordStatus) + getProposalStatusLabel(nextStatus, isByRecordStatus) ] || [] ) ); - setRemainingTokens(unfetchedTokens); - setStatusIndex(newIndex); + setRemainingTokens([...remainingTokens, ...nextStatusTokens]); + setStatusIndex(nextIndex); if (!values(proposals).length) { // If no proposals are fetched yet. // Continue the fetching cycle to fetch the first page. @@ -250,6 +315,7 @@ export default function useProposalsBatch({ } return false; }); + setRemainingTokens(unfetchedTokens); setStatusIndex(index); if (isByRecordStatus) { @@ -273,10 +339,13 @@ export default function useProposalsBatch({ tokens && tokens.length && tokens.length % INVENTORY_PAGE_SIZE === 0; const onFetchMoreProposals = useCallback(() => { - if (isEmpty(remainingTokens) && isAnotherInventoryCallRequired) + if ( + remainingTokens.length < proposalPageSize && + isAnotherInventoryCallRequired + ) return send(START); return send(VERIFY); - }, [send, remainingTokens, isAnotherInventoryCallRequired]); + }, [send, remainingTokens, proposalPageSize, isAnotherInventoryCallRequired]); const anyError = error || state.error; useThrowError(anyError); diff --git a/teste2e/cypress/e2e/records/recordsList.js b/teste2e/cypress/e2e/records/recordsList.js index 229fce5c7..6c41a39f0 100644 --- a/teste2e/cypress/e2e/records/recordsList.js +++ b/teste2e/cypress/e2e/records/recordsList.js @@ -40,7 +40,7 @@ describe("Records list", () => { }); cy.wait("@records.records"); // each proposal should be rendered accordingly to inventory response - cy.assertListLengthByTestId("record-title", RECORDS_PAGE_SIZE + 3) // first records batch + cy.assertListLengthByTestId("record-title", RECORDS_PAGE_SIZE) // first records batch .each(([{ id }], position) => { const tokens = getTokensByStatusTab(inventory, "Under Review"); const expectedToken = shortRecordToken(tokens[position]); @@ -50,22 +50,27 @@ describe("Records list", () => { it("can render records and inventory pagination correctly", () => { cy.visit(`/`); cy.wait("@ticketvote.inventory"); + // Fetch 'started', 'authorized' and 'unauthorized' proposals cy.wait("@records.records"); - cy.assertListLengthByTestId("record-title", 8); + // 3 items of started status and 2 items of unauthorized status + cy.assertListLengthByTestId("record-title", 5); cy.scrollTo("bottom"); cy.wait("@records.records"); - cy.assertListLengthByTestId("record-title", 13); + cy.assertListLengthByTestId("record-title", 10); cy.scrollTo("bottom"); cy.wait("@records.records"); - cy.assertListLengthByTestId("record-title", 18); + cy.assertListLengthByTestId("record-title", 15); cy.scrollTo("bottom"); cy.wait("@records.records"); - cy.assertListLengthByTestId("record-title", 23); + cy.assertListLengthByTestId("record-title", 20); // finished first inventory page cy.scrollTo("bottom"); cy.wait("@ticketvote.inventory").its("request.body.page").should("eq", 2); cy.wait("@records.records"); // records from second inventory page + cy.assertListLengthByTestId("record-title", 25); + cy.scrollTo("bottom"); + cy.wait("@records.records"); cy.assertListLengthByTestId("record-title", 28); cy.scrollTo("bottom"); // wait to see if no requests are done, since inventory is fully fetched @@ -80,7 +85,7 @@ describe("Records list", () => { // navigate to in discussion tab cy.findByTestId("tab-0").click(); cy.wait("@records.records"); - cy.assertListLengthByTestId("record-title", 8); + cy.assertListLengthByTestId("record-title", 5); }); it("can list legacy proposals", () => { // for approved proposals From 2d11125798a4f9210643cefcd110c3aebf645454 Mon Sep 17 00:00:00 2001 From: Viet Anh Date: Fri, 27 Aug 2021 15:31:21 +0700 Subject: [PATCH 2/6] add condition variable, fix scanNextStatusTokens function bug, remove redundant comment --- src/hooks/api/useProposalsBatch.js | 44 ++++++++++++++---------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/hooks/api/useProposalsBatch.js b/src/hooks/api/useProposalsBatch.js index 17daa650d..bdb0fa05b 100644 --- a/src/hooks/api/useProposalsBatch.js +++ b/src/hooks/api/useProposalsBatch.js @@ -134,33 +134,26 @@ export default function useProposalsBatch({ const hasRemainingTokens = !isEmpty(remainingTokens); const scanNextStatusTokens = (index, oldTokens) => { - if (index < currentStatuses.length) { - const status = currentStatuses[index]; - const newTokens = getUnfetchedTokens( - proposals, - uniq( - allByStatus[getProposalStatusLabel(status, isByRecordStatus)] || [] - ) - ); - const tokens = [...oldTokens, ...newTokens]; - if (tokens.length < proposalPageSize) { - // scan the next status. - return scanNextStatusTokens(index + 1, tokens); - } - return { - index, - tokens - }; + const status = currentStatuses[index]; + const newTokens = getUnfetchedTokens( + proposals, + uniq(allByStatus[getProposalStatusLabel(status, isByRecordStatus)] || []) + ); + + const tokens = [...oldTokens, ...newTokens]; + if (tokens.length < proposalPageSize && index < currentStatuses.length) { + return scanNextStatusTokens(index + 1, tokens); } - return { index, tokens: [] }; + return { + index, + tokens + }; }; const [state, send] = useFetchMachine({ actions: { initial: () => send(START), start: () => { - // If remaining tokens length is greater than proposal page size. - // Fetch proposals. if (remainingTokens.length >= proposalPageSize) return send(VERIFY); // If remaining tokens length is smaller than proposal page size. @@ -172,13 +165,13 @@ export default function useProposalsBatch({ allByStatus[ getProposalStatusLabel(currentStatus, isByRecordStatus) ] || []; - if ( + const scanTokensCondition = initializedInventory && !( currentStatusTokens.length % INVENTORY_PAGE_SIZE === 0 && currentStatusTokens.length > 0 - ) - ) { + ); + if (scanTokensCondition) { const { index, tokens } = scanNextStatusTokens( statusIndex + 1, remainingTokens @@ -219,10 +212,12 @@ export default function useProposalsBatch({ return send(VERIFY); }); + return send(FETCH); }, verify: () => { if (!hasRemainingTokens) return send(RESOLVE, { proposals }); + const [tokensToFetch, next] = getTokensForProposalsPagination( remainingTokens, proposalPageSize @@ -254,9 +249,11 @@ export default function useProposalsBatch({ return send(VERIFY); } } + return send(RESOLVE); }) .catch((e) => send(REJECT, e)); + return send(FETCH); }, done: () => { @@ -303,6 +300,7 @@ export default function useProposalsBatch({ let unfetchedTokens = [], index = 0; const statuses = newStatuses || currentStatuses; + const foundPreviousSessionStatus = statuses.find((status, i) => { const statusLabel = getProposalStatusLabel(status, isByRecordStatus); unfetchedTokens = getUnfetchedTokens( From ad10ad3f63343ff36ee103cc80ae0048d9d3fdd7 Mon Sep 17 00:00:00 2001 From: Viet Anh Date: Sat, 28 Aug 2021 23:18:39 +0700 Subject: [PATCH 3/6] reproduce scan tokens logic --- src/hooks/api/useProposalsBatch.js | 85 ++++++++++++------------------ 1 file changed, 33 insertions(+), 52 deletions(-) diff --git a/src/hooks/api/useProposalsBatch.js b/src/hooks/api/useProposalsBatch.js index bdb0fa05b..8a4f7532e 100644 --- a/src/hooks/api/useProposalsBatch.js +++ b/src/hooks/api/useProposalsBatch.js @@ -115,6 +115,7 @@ export default function useProposalsBatch({ const allByStatus = useSelector( isByRecordStatus ? sel.allByRecordStatus : sel.allByVoteStatus ); + const tokens = useMemo( () => allByStatus[getProposalStatusLabel(currentStatus, isByRecordStatus)] || @@ -159,19 +160,12 @@ export default function useProposalsBatch({ // If remaining tokens length is smaller than proposal page size. // Find more tokens from inventory or scan from the next status - // Condition to scan: inventory is initialized and - // the tokens are able to be fetched from the next page - const currentStatusTokens = - allByStatus[ - getProposalStatusLabel(currentStatus, isByRecordStatus) - ] || []; - const scanTokensCondition = + // scanNextStatus: inventory is initialized and + // there are no tokens to be fetched from the next page + const scanNextStatus = initializedInventory && - !( - currentStatusTokens.length % INVENTORY_PAGE_SIZE === 0 && - currentStatusTokens.length > 0 - ); - if (scanTokensCondition) { + !(tokens.length % INVENTORY_PAGE_SIZE === 0 && tokens.length > 0); + if (scanNextStatus) { const { index, tokens } = scanNextStatusTokens( statusIndex + 1, remainingTokens @@ -199,16 +193,32 @@ export default function useProposalsBatch({ currentStatus, isByRecordStatus ); - const newTokens = (isByRecordStatus ? records : votes)[ - proposalStatusLabel - ]; + const newTokensByStatus = isByRecordStatus ? records : votes; + const newTokens = newTokensByStatus[proposalStatusLabel]; const tokens = [...newTokens, ...remainingTokens]; setRemainingTokens(tokens); + + // Go to the next status when the remaining tokens still be smaller + // than proposal page size and current status is not the last one. if ( tokens.length < proposalPageSize && statusIndex + 1 < currentStatuses.length - ) - return send(RESOLVE); + ) { + const nextIndex = statusIndex + 1; + const nextStatus = currentStatuses[nextIndex]; + const nextStatusTokens = getUnfetchedTokens( + proposals, + uniq( + (page ? allByStatus : newTokensByStatus)[ + getProposalStatusLabel(nextStatus, isByRecordStatus) + ] || [] + ) + ); + setRemainingTokens([...tokens, ...nextStatusTokens]); + setStatusIndex(nextIndex); + + return send(START); + } return send(VERIFY); }); @@ -217,7 +227,6 @@ export default function useProposalsBatch({ }, verify: () => { if (!hasRemainingTokens) return send(RESOLVE, { proposals }); - const [tokensToFetch, next] = getTokensForProposalsPagination( remainingTokens, proposalPageSize @@ -256,32 +265,7 @@ export default function useProposalsBatch({ return send(FETCH); }, - done: () => { - // If the remaining tokens is smaller than proposal page size and have not scanned status. - // Check the new status and set up new tokens - if ( - remainingTokens.length < proposalPageSize && - statusIndex + 1 < currentStatuses.length - ) { - const nextIndex = statusIndex + 1; - const nextStatus = currentStatuses[nextIndex]; - const nextStatusTokens = getUnfetchedTokens( - proposals, - uniq( - allByStatus[ - getProposalStatusLabel(nextStatus, isByRecordStatus) - ] || [] - ) - ); - setRemainingTokens([...remainingTokens, ...nextStatusTokens]); - setStatusIndex(nextIndex); - if (!values(proposals).length) { - // If no proposals are fetched yet. - // Continue the fetching cycle to fetch the first page. - return send(START); - } - } - } + done: () => {} }, initialValues: { status: "idle", @@ -333,17 +317,14 @@ export default function useProposalsBatch({ state.status === "success" && !getUnfetchedTokens(proposals, tokens).length; - const isAnotherInventoryCallRequired = + const isAnotherTokensScanningRequired = tokens && tokens.length && tokens.length % INVENTORY_PAGE_SIZE === 0; const onFetchMoreProposals = useCallback(() => { - if ( - remainingTokens.length < proposalPageSize && - isAnotherInventoryCallRequired - ) - return send(START); + if (remainingTokens.length < proposalPageSize) return send(START); + return send(VERIFY); - }, [send, remainingTokens, proposalPageSize, isAnotherInventoryCallRequired]); + }, [send, remainingTokens, proposalPageSize]); const anyError = error || state.error; useThrowError(anyError); @@ -363,7 +344,7 @@ export default function useProposalsBatch({ onRestartMachine, onFetchMoreProposals, hasMoreProposals: !!remainingTokens.length && !!values(proposals).length, - isProposalsBatchComplete: isFetchDone && !isAnotherInventoryCallRequired, + isProposalsBatchComplete: isFetchDone && !isAnotherTokensScanningRequired, machineCurrentState: state.status }; } From e70c6803c6f3352edfed5f9ae10b1358cba4eff7 Mon Sep 17 00:00:00 2001 From: Viet Anh Date: Tue, 31 Aug 2021 00:24:44 +0700 Subject: [PATCH 4/6] batch pagination testing --- teste2e/cypress/e2e/records/recordsList.js | 134 ++++++++++++++++----- 1 file changed, 104 insertions(+), 30 deletions(-) diff --git a/teste2e/cypress/e2e/records/recordsList.js b/teste2e/cypress/e2e/records/recordsList.js index 6c41a39f0..cc3ae511d 100644 --- a/teste2e/cypress/e2e/records/recordsList.js +++ b/teste2e/cypress/e2e/records/recordsList.js @@ -10,6 +10,7 @@ const statusByTab = { }; const RECORDS_PAGE_SIZE = 5; +const INVENTORY_PAGE_SIZE = 20; const getTokensByStatusTab = (inventory, currentTab) => statusByTab[currentTab] @@ -19,7 +20,110 @@ const getTokensByStatusTab = (inventory, currentTab) => ) : []; +const underReviewPaginationCases = [ + { + title: "Zero page", + inventory: { + authorized: 0, + started: 0, + unauthorized: 1 + }, + } , { + title: "Fill up statuses", + inventory: { + authorized: 1, + started: 1, + unauthorized: 1 + }, + } , { + title: "1 page", + inventory: { + authorized: 10, + started: 3, + unauthorized: 25 + }, + }, { + title: "2 page", + inventory: { + authorized: 20, + started: 3, + unauthorized: 40 + }, + } +]; + +const scanPage = (inventory) => { + cy.visit(`/`); + const started = inventory.started || 0; + const authorized = inventory.authorized || 0; + const unauthorized = inventory.unauthorized || 0; + const total = started + authorized + unauthorized; + const statuses = [started, authorized, unauthorized]; + let page = 1, statusIndex = 0, oldFilledStatusTokens = 0, oldInventoryPage; + + const scanStatus = (currentStatusIndex, willFetchedTokens) => { + const nextStatusIndex = currentStatusIndex + 1; + if (nextStatusIndex >= statuses.length) { + return currentStatusIndex; + } + const nextStatusTokens = statuses[nextStatusIndex] + oldFilledStatusTokens += statuses[currentStatusIndex]; + if (nextStatusTokens + oldFilledStatusTokens < willFetchedTokens) { + return scanStatus(nextStatusIndex) + } + return nextStatusIndex + } + + do { + if (!statuses[statusIndex]) { + return + } + const tokensInStatus = statuses[statusIndex]; + const willFetchedTokens = page * RECORDS_PAGE_SIZE; + + if (willFetchedTokens > oldFilledStatusTokens + tokensInStatus && statusIndex +1 < statuses.length) { + // switch to next status + statusIndex = scanStatus(statusIndex, willFetchedTokens); + oldInventoryPage = 0; + } + const inventoryPage = Math.floor((willFetchedTokens - oldFilledStatusTokens) / INVENTORY_PAGE_SIZE); + if (page === 1) { + // fist page fetch all statuses + cy.wait("@ticketvote.inventory"); + } else if (inventoryPage !== oldInventoryPage && tokensInStatus >= inventoryPage * INVENTORY_PAGE_SIZE) { + // fetch next page + oldInventoryPage = inventoryPage; + cy.wait("@ticketvote.inventory").its("request.body.page").should("eq", inventoryPage + 1); + } + cy.wait("@records.records"); + + if (willFetchedTokens > total) { + cy.assertListLengthByTestId("record-title", total); + cy.scrollTo("bottom"); + // wait to see if no requests are done, since inventory is fully fetched + cy.wait(1000); + cy.assertListLengthByTestId("record-title", total); + } else { + cy.assertListLengthByTestId("record-title", RECORDS_PAGE_SIZE * page); + cy.scrollTo("bottom"); + } + page += 1; + } while (page <= Math.ceil(total / RECORDS_PAGE_SIZE)); +} + describe("Records list", () => { + underReviewPaginationCases.forEach((config) => { + describe(`Under review render records and inventory pagination correctly: ${config.title}`, () => { + before(() => { + cy.middleware("ticketvote.inventory", config.inventory); + cy.middleware("records.records"); + }); + it("Render", () => { + scanPage(config.inventory) + }) + }) + }) + describe("proposals list", () => { beforeEach(() => { cy.middleware("ticketvote.inventory", { @@ -47,36 +151,6 @@ describe("Records list", () => { expect(id).to.have.string(expectedToken); }); }); - it("can render records and inventory pagination correctly", () => { - cy.visit(`/`); - cy.wait("@ticketvote.inventory"); - // Fetch 'started', 'authorized' and 'unauthorized' proposals - cy.wait("@records.records"); - // 3 items of started status and 2 items of unauthorized status - cy.assertListLengthByTestId("record-title", 5); - cy.scrollTo("bottom"); - cy.wait("@records.records"); - cy.assertListLengthByTestId("record-title", 10); - cy.scrollTo("bottom"); - cy.wait("@records.records"); - cy.assertListLengthByTestId("record-title", 15); - cy.scrollTo("bottom"); - cy.wait("@records.records"); - cy.assertListLengthByTestId("record-title", 20); - // finished first inventory page - cy.scrollTo("bottom"); - cy.wait("@ticketvote.inventory").its("request.body.page").should("eq", 2); - cy.wait("@records.records"); - // records from second inventory page - cy.assertListLengthByTestId("record-title", 25); - cy.scrollTo("bottom"); - cy.wait("@records.records"); - cy.assertListLengthByTestId("record-title", 28); - cy.scrollTo("bottom"); - // wait to see if no requests are done, since inventory is fully fetched - cy.wait(1000); - cy.assertListLengthByTestId("record-title", 28); - }); it("can switch tabs and load proposals correctly", () => { cy.visit("/?tab=approved"); cy.wait("@ticketvote.inventory"); From 61a94d27e901ba91030137aa225e57b6017296ec Mon Sep 17 00:00:00 2001 From: Viet Anh Date: Tue, 31 Aug 2021 12:09:04 +0700 Subject: [PATCH 5/6] fix e2e test: records and inventory pagination --- teste2e/cypress/e2e/records/recordsList.js | 203 +++++++++++---------- 1 file changed, 107 insertions(+), 96 deletions(-) diff --git a/teste2e/cypress/e2e/records/recordsList.js b/teste2e/cypress/e2e/records/recordsList.js index cc3ae511d..59e94dbdd 100644 --- a/teste2e/cypress/e2e/records/recordsList.js +++ b/teste2e/cypress/e2e/records/recordsList.js @@ -10,7 +10,6 @@ const statusByTab = { }; const RECORDS_PAGE_SIZE = 5; -const INVENTORY_PAGE_SIZE = 20; const getTokensByStatusTab = (inventory, currentTab) => statusByTab[currentTab] @@ -20,109 +19,121 @@ const getTokensByStatusTab = (inventory, currentTab) => ) : []; -const underReviewPaginationCases = [ - { - title: "Zero page", - inventory: { - authorized: 0, - started: 0, - unauthorized: 1 - }, - } , { - title: "Fill up statuses", - inventory: { - authorized: 1, - started: 1, - unauthorized: 1 - }, - } , { - title: "1 page", - inventory: { - authorized: 10, - started: 3, - unauthorized: 25 - }, - }, { - title: "2 page", - inventory: { - authorized: 20, - started: 3, - unauthorized: 40 - }, - } -]; - -const scanPage = (inventory) => { - cy.visit(`/`); - const started = inventory.started || 0; - const authorized = inventory.authorized || 0; - const unauthorized = inventory.unauthorized || 0; - const total = started + authorized + unauthorized; - const statuses = [started, authorized, unauthorized]; - let page = 1, statusIndex = 0, oldFilledStatusTokens = 0, oldInventoryPage; - - const scanStatus = (currentStatusIndex, willFetchedTokens) => { - const nextStatusIndex = currentStatusIndex + 1; - if (nextStatusIndex >= statuses.length) { - return currentStatusIndex; - } - const nextStatusTokens = statuses[nextStatusIndex] - oldFilledStatusTokens += statuses[currentStatusIndex]; - if (nextStatusTokens + oldFilledStatusTokens < willFetchedTokens) { - return scanStatus(nextStatusIndex) - } - return nextStatusIndex - } - - do { - if (!statuses[statusIndex]) { - return - } - const tokensInStatus = statuses[statusIndex]; - const willFetchedTokens = page * RECORDS_PAGE_SIZE; - - if (willFetchedTokens > oldFilledStatusTokens + tokensInStatus && statusIndex +1 < statuses.length) { - // switch to next status - statusIndex = scanStatus(statusIndex, willFetchedTokens); - oldInventoryPage = 0; - } - const inventoryPage = Math.floor((willFetchedTokens - oldFilledStatusTokens) / INVENTORY_PAGE_SIZE); - if (page === 1) { - // fist page fetch all statuses +describe("Records list", () => { + describe("records and inventory pagination", () => { + before(() => { + cy.middleware("ticketvote.inventory", { + authorized: 0, + started: 0, + unauthorized: 1 + }); + cy.middleware("records.records"); + }); + it("work correct with 0 item in some statuses.", () => { + cy.visit(`/`); cy.wait("@ticketvote.inventory"); - } else if (inventoryPage !== oldInventoryPage && tokensInStatus >= inventoryPage * INVENTORY_PAGE_SIZE) { - // fetch next page - oldInventoryPage = inventoryPage; - cy.wait("@ticketvote.inventory").its("request.body.page").should("eq", inventoryPage + 1); - } - cy.wait("@records.records"); - - if (willFetchedTokens > total) { - cy.assertListLengthByTestId("record-title", total); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 1); cy.scrollTo("bottom"); // wait to see if no requests are done, since inventory is fully fetched cy.wait(1000); - cy.assertListLengthByTestId("record-title", total); - } else { - cy.assertListLengthByTestId("record-title", RECORDS_PAGE_SIZE * page); + cy.assertListLengthByTestId("record-title", 1); + }) + }); + + describe("records and inventory pagination", () => { + before(() => { + cy.middleware("ticketvote.inventory", { + authorized: 1, + started: 1, + unauthorized: 1 + }); + cy.middleware("records.records"); + }); + it("do not lose any status.", () => { + cy.visit(`/`); + cy.wait("@ticketvote.inventory"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 3); cy.scrollTo("bottom"); - } - page += 1; - } while (page <= Math.ceil(total / RECORDS_PAGE_SIZE)); -} + // wait to see if no requests are done, since inventory is fully fetched + cy.wait(1000); + cy.assertListLengthByTestId("record-title", 3); + }) + }); -describe("Records list", () => { - underReviewPaginationCases.forEach((config) => { - describe(`Under review render records and inventory pagination correctly: ${config.title}`, () => { - before(() => { - cy.middleware("ticketvote.inventory", config.inventory); - cy.middleware("records.records"); + describe("records and inventory pagination", () => { + before(() => { + cy.middleware("ticketvote.inventory", { + authorized: 20, + started: 3, + unauthorized: 45 }); - it("Render", () => { - scanPage(config.inventory) - }) + cy.middleware("records.records"); + }); + it("scan inventory pages correct", () => { + cy.visit(`/`); + cy.wait("@ticketvote.inventory"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 5); + // 3 started and 2 authorized + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 10); + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 15); + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 20); + cy.scrollTo("bottom"); + // prepare to fetch 25 items: 3 started, 20 authorized and 2 unauthorized + // scan inventory: page 2 of authorized + cy.wait("@ticketvote.inventory").its("request.body") + .should("deep.eq", {page: 2,status : 2}); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 25); + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 30); + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 35); + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 40); + cy.scrollTo("bottom"); + // prepare to fetch 45 items: 3 started, 20 authorized and 22 unauthorized + // scan inventory: page 2 of unauthorized + cy.wait("@ticketvote.inventory").its("request.body") + .should("deep.eq", {page: 2,status : 1}); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 45); + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 50); + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 55); + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 60); + cy.scrollTo("bottom"); + // prepare to fetch 65 items: 3 started, 20 authorized and 42 unauthorized + // scan inventory: page 3 of unauthorized + cy.wait("@ticketvote.inventory").its("request.body") + .should("deep.eq", {page: 3,status : 1}); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 65); + cy.scrollTo("bottom"); + cy.wait("@records.records"); + cy.assertListLengthByTestId("record-title", 68); + cy.scrollTo("bottom"); + // wait to see if no requests are done, since inventory is fully fetched + cy.wait(1000); + cy.assertListLengthByTestId("record-title", 68); }) - }) + }); describe("proposals list", () => { beforeEach(() => { From 26364123334806687e2de85f3b360260c2cde2cc Mon Sep 17 00:00:00 2001 From: Viet Anh Date: Wed, 1 Sep 2021 00:46:19 +0700 Subject: [PATCH 6/6] clean up code --- teste2e/cypress/e2e/records/recordsList.js | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/teste2e/cypress/e2e/records/recordsList.js b/teste2e/cypress/e2e/records/recordsList.js index 59e94dbdd..f6c47fca4 100644 --- a/teste2e/cypress/e2e/records/recordsList.js +++ b/teste2e/cypress/e2e/records/recordsList.js @@ -21,15 +21,16 @@ const getTokensByStatusTab = (inventory, currentTab) => describe("Records list", () => { describe("records and inventory pagination", () => { - before(() => { + it("work correct with 0 item in some statuses.", () => { + // emulate api cy.middleware("ticketvote.inventory", { authorized: 0, started: 0, unauthorized: 1 }); cy.middleware("records.records"); - }); - it("work correct with 0 item in some statuses.", () => { + + // do testing cy.visit(`/`); cy.wait("@ticketvote.inventory"); cy.wait("@records.records"); @@ -38,19 +39,18 @@ describe("Records list", () => { // wait to see if no requests are done, since inventory is fully fetched cy.wait(1000); cy.assertListLengthByTestId("record-title", 1); - }) - }); + }); - describe("records and inventory pagination", () => { - before(() => { + it("do not lose any status.", () => { + // emulate api cy.middleware("ticketvote.inventory", { authorized: 1, started: 1, unauthorized: 1 }); cy.middleware("records.records"); - }); - it("do not lose any status.", () => { + + // do testing cy.visit(`/`); cy.wait("@ticketvote.inventory"); cy.wait("@records.records"); @@ -59,19 +59,18 @@ describe("Records list", () => { // wait to see if no requests are done, since inventory is fully fetched cy.wait(1000); cy.assertListLengthByTestId("record-title", 3); - }) - }); + }); - describe("records and inventory pagination", () => { - before(() => { + it("scan inventory pages correctly", () => { + // emulate api cy.middleware("ticketvote.inventory", { authorized: 20, started: 3, unauthorized: 45 }); cy.middleware("records.records"); - }); - it("scan inventory pages correct", () => { + + // do testing cy.visit(`/`); cy.wait("@ticketvote.inventory"); cy.wait("@records.records"); @@ -90,7 +89,7 @@ describe("Records list", () => { // prepare to fetch 25 items: 3 started, 20 authorized and 2 unauthorized // scan inventory: page 2 of authorized cy.wait("@ticketvote.inventory").its("request.body") - .should("deep.eq", {page: 2,status : 2}); + .should("deep.eq", {page: 2,status : 2}); cy.wait("@records.records"); cy.assertListLengthByTestId("record-title", 25); cy.scrollTo("bottom"); @@ -132,7 +131,7 @@ describe("Records list", () => { // wait to see if no requests are done, since inventory is fully fetched cy.wait(1000); cy.assertListLengthByTestId("record-title", 68); - }) + }); }); describe("proposals list", () => {