filters transaction feeds by date range

Before continuing, make sure you have read the Transaction Feeds Overview & Setup lesson first.

describe("filters transaction feeds by date range", () => {
  if (isMobile()) {
    it("closes date range picker modal", () => {
      cy.getBySelLike("filter-date-range-button").click({ force: true })
      cy.get(".Cal__Header__root").should("be.visible")
      cy.visualSnapshot("Mobile Open Date Range Picker")
      cy.getBySel("date-range-filter-drawer-close").click()
      cy.get(".Cal__Header__root").should("not.exist")
      cy.visualSnapshot("Mobile Close Date Range Picker")
    })
  }

  _.each(feedViews, (feed, feedName) => {
    it(`filters ${feedName} transaction feed by date range`, () => {
      cy.database("find", "transactions").then((transaction: Transaction) => {
        const dateRangeStart = startOfDay(new Date(transaction.createdAt))
        const dateRangeEnd = endOfDayUTC(addDays(dateRangeStart, 1))

        cy.getBySelLike(feed.tab).click().should("have.class", "Mui-selected")

        cy.wait(`@${feed.routeAlias}`)
          .its("response.body.results")
          .as("unfilteredResults")

        cy.pickDateRange(dateRangeStart, dateRangeEnd)

        cy.wait(`@${feed.routeAlias}`)
          .its("response.body.results")
          .then((transactions: Transaction[]) => {
            cy.getBySelLike("transaction-item").should(
              "have.length",
              transactions.length
            )

            transactions.forEach(({ createdAt }) => {
              const createdAtDate = startOfDayUTC(new Date(createdAt))

              expect(
                isWithinInterval(createdAtDate, {
                  start: startOfDayUTC(dateRangeStart),
                  end: dateRangeEnd,
                }),
                `transaction created date (${createdAtDate.toISOString()})
                  is within ${dateRangeStart.toISOString()}
                  and ${dateRangeEnd.toISOString()}`
              ).to.equal(true)
            })

            cy.visualSnapshot("Date Range Filtered Transactions")
          })

        cy.log("Clearing date range filter. Data set should revert")
        cy.getBySelLike("filter-date-clear-button").click({
          force: true,
        })
        cy.getBySelLike("filter-date-range-button").should("contain", "ALL")

        cy.get("@unfilteredResults").then((unfilteredResults) => {
          cy.wait(`@${feed.routeAlias}`)
            .its("response.body.results")
            .should("deep.equal", unfilteredResults)
          cy.visualSnapshot("Unfiltered Transactions")
        })
      })
    })

    it(`does not show ${feedName} transactions for out of range date limits`, () => {
      const dateRangeStart = startOfDay(new Date(2014, 1, 1))
      const dateRangeEnd = endOfDayUTC(addDays(dateRangeStart, 1))

      cy.getBySelLike(feed.tab).click()
      cy.wait(`@${feed.routeAlias}`)

      cy.pickDateRange(dateRangeStart, dateRangeEnd)
      cy.wait(`@${feed.routeAlias}`)

      cy.getBySelLike("transaction-item").should("have.length", 0)
      cy.getBySel("empty-list-header").should("contain", "No Transactions")
      cy.getBySelLike("empty-create-transaction-button")
        .should("have.attr", "href", "/transaction/new")
        .contains("create a transaction", { matchCase: false })
        .should("have.css", { "text-transform": "uppercase" })
      cy.visualSnapshot("No Transactions")
    })
  })
})

You can find out more information about the custom Cypress commands used in this test here.

First, we are checking to see if our test is being run inside of a mobile viewport. If so, we ensure that the data range picker works properly on a mobile device by clicking on it to open it, confirming that it is open, and then closing it.

if (isMobile()) {
  it("closes date range picker modal", () => {
    cy.getBySelLike("filter-date-range-button").click({ force: true })
    cy.get(".Cal__Header__root").should("be.visible")
    cy.visualSnapshot("Mobile Open Date Range Picker")
    cy.getBySel("date-range-filter-drawer-close").click()
    cy.get(".Cal__Header__root").should("not.exist")
    cy.visualSnapshot("Mobile Close Date Range Picker")
  })
}

Next, we loop through each property inside the feedViews object, which we defined in the beforeEach() at the top of the spec file.

const feedViews = {
    public: {
      tab: "public-tab",
      tabLabel: "everyone",
      routeAlias: "publicTransactions",
      service: "publicTransactionService",
    },
    contacts: {
      tab: "contacts-tab",
      tabLabel: "friends",
      routeAlias: "contactsTransactions",
      service: "contactTransactionService",
    },
    personal: {
      tab: "personal-tab",
      tabLabel: "mine",
      routeAlias: "personalTransactions",
      service: "personalTransactionService",
    },
  };

// ..

_.each(feedViews, (feed, feedName) => {

We then create a test for each feedView dynamically.

it.only(`filters ${feedName} transaction feed by date range`, () => {

Next, we use a custom Cypress command cy.database() to find some transactions from the database.

cy.database("find", "transactions").then((transaction: Transaction) => {

Then, we click on the appropriate tab for our feed.

cy.getBySelLike(feed.tab).click().should("have.class", "Mui-selected")

Next we wait on the intercept associated with the feed.

cy.wait(`@${feed.routeAlias}`)
  .its("response.body.results")
  .as("unfilteredResults")

Next, we use another custom Cypress command cy.pickDateRange() to pick select the dates we want.

cy.pickDateRange(dateRangeStart, dateRangeEnd)

Then, we wait on the intercept associated with the feed and grab the results from the reponse.

cy.wait(`@${feed.routeAlias}`).its("response.body.results")

We then confirm that all of the results are displayed in the UI.

cy.getBySelLike("transaction-item").should("have.length", transactions.length)

Then we loop through all of the transactions and make sure that all of the transaction dates are within the correct range.

  • startOfDayUTC is a utility function that can be found in src/utils/transactionUtils.ts
  • isWithinInterval is a function from the date-fns library.
transactions.forEach(({ createdAt }) => {
  const createdAtDate = startOfDayUTC(new Date(createdAt))

  expect(
    isWithinInterval(createdAtDate, {
      start: startOfDayUTC(dateRangeStart),
      end: dateRangeEnd,
    }),
    `transaction created date (${createdAtDate.toISOString()})
                  is within ${dateRangeStart.toISOString()}
                  and ${dateRangeEnd.toISOString()}`
  ).to.equal(true)
})

We then use cy.log() to output a custom message to the Cypress Command Log.

cy.log("Clearing date range filter. Data set should revert")

Next, we clear the date range picker.

cy.getBySelLike("filter-date-clear-button").click({
  force: true,
})

Finally, we make sure that all of the transactions are displayed now that we have cleared the date range picker, meaning that we are no longer filtering the results.

cy.get("@unfilteredResults").then((unfilteredResults) => {
  cy.wait(`@${feed.routeAlias}`)
    .its("response.body.results")
    .should("deep.equal", unfilteredResults)
  cy.visualSnapshot("Unfiltered Transactions")
})