From 32dea27ef4a5f72df018a12381fed10ff0367864 Mon Sep 17 00:00:00 2001
From: Himanshu Aggarwal <aggarwah@mcmaster.ca>
Date: Tue, 22 Mar 2022 17:29:24 -0400
Subject: [PATCH] Add tests for search and filters

---
 src/cryptometrics/components/button/Button.js |   3 +-
 .../components/button/FilterButton.js         |   1 +
 .../components/cards/CryptoChartCard.js       |  16 +-
 .../components/dropdown/FilterDropdownItem.js |   1 +
 src/cryptometrics/components/inputs/Input.js  |   2 +
 .../components/radio/RadioForm.js             |   1 +
 .../cypress/integration/home/filter.spec.js   |  58 ++++
 .../cypress/integration/home/search.spec.js   |  44 +++
 .../cypress/integration/home/table.spec.js    |   2 +-
 src/cryptometrics/pages/index.js              | 283 ++++++++++--------
 10 files changed, 276 insertions(+), 135 deletions(-)
 create mode 100644 src/cryptometrics/cypress/integration/home/filter.spec.js
 create mode 100644 src/cryptometrics/cypress/integration/home/search.spec.js

diff --git a/src/cryptometrics/components/button/Button.js b/src/cryptometrics/components/button/Button.js
index 882cc5c..dea0607 100644
--- a/src/cryptometrics/components/button/Button.js
+++ b/src/cryptometrics/components/button/Button.js
@@ -13,7 +13,7 @@ import classNames from "classnames";
  *   </Button>
  * )
  */
-function Button({ children, className, onClick, type, disabled }) {
+function Button({ children, className, onClick, type, disabled, id }) {
   return (
     <button
       className={classNames("py-2 px-5 rounded-xl", className, {
@@ -21,6 +21,7 @@ function Button({ children, className, onClick, type, disabled }) {
       })}
       onClick={disabled ? undefined : onClick}
       type={type ? type : "button"}
+      id={id ? id : undefined}
     >
       {children}
     </button>
diff --git a/src/cryptometrics/components/button/FilterButton.js b/src/cryptometrics/components/button/FilterButton.js
index e007282..5885e33 100644
--- a/src/cryptometrics/components/button/FilterButton.js
+++ b/src/cryptometrics/components/button/FilterButton.js
@@ -6,6 +6,7 @@ export default function FilterButton({ icon, onClick }) {
     <Button
       className="mx-1 mt-2 font-sans font-normal bg-dark-600 rounded-lg dark:text-neutral-200 dark:hover:text-indigo-600 inline-flex h-10 w-10 justify-center items-center whitespace-nowrap"
       onClick={onClick}
+      id="filter-button"
     >
       <span className="text-white">{icon}</span>
     </Button>
diff --git a/src/cryptometrics/components/cards/CryptoChartCard.js b/src/cryptometrics/components/cards/CryptoChartCard.js
index 239b604..791bfe0 100644
--- a/src/cryptometrics/components/cards/CryptoChartCard.js
+++ b/src/cryptometrics/components/cards/CryptoChartCard.js
@@ -62,12 +62,18 @@ function CryptoChartCard({
                   ></Image>
                 </div>
                 <div>
-                  <p className="text-3xl font-poppins font-bold text-gray-700 dark:text-gray-100">
+                  <p
+                    className="text-3xl font-poppins font-bold text-gray-700 dark:text-gray-100"
+                    id="currency-name"
+                  >
                     {currencyName || (
                       <PlaceholderSkeleton className="h-9 w-[60%]" />
                     )}
                   </p>
-                  <p className="text-lg font-poppins font-medium text-gray-700 dark:text-gray-100">
+                  <p
+                    className="text-lg font-poppins font-medium text-gray-700 dark:text-gray-100"
+                    id="currency-symbol"
+                  >
                     {symbol}
                   </p>
                 </div>
@@ -83,7 +89,10 @@ function CryptoChartCard({
               <div className="flex flex-col h-[9.5rem]">
                 <div className="mt-auto">
                   <div className="flex justify-end">
-                    <p className="text-4xl font-poppins font-bold text-black dark:text-white">
+                    <p
+                      className="text-4xl font-poppins font-bold text-black dark:text-white"
+                      id="currency-price"
+                    >
                       {info || (
                         <PlaceholderSkeleton className="h-9 w-[200px]" />
                       )}
@@ -95,6 +104,7 @@ function CryptoChartCard({
                         "text-lg font-poppins font-bold",
                         detailColor
                       )}
+                      id="currency-price-change-percentage"
                     >
                       {detail || <PlaceholderSkeleton className="h-4 w-20" />}
                     </p>
diff --git a/src/cryptometrics/components/dropdown/FilterDropdownItem.js b/src/cryptometrics/components/dropdown/FilterDropdownItem.js
index d9c4730..a01f01c 100644
--- a/src/cryptometrics/components/dropdown/FilterDropdownItem.js
+++ b/src/cryptometrics/components/dropdown/FilterDropdownItem.js
@@ -21,6 +21,7 @@ function FilterDropdownItem({
         }
       )}
       onClick={disabled || !onClick ? undefined : () => onClick(id)}
+      id={`${id}-option`}
     >
       <div className="flex flex-row items-center">
         {children}
diff --git a/src/cryptometrics/components/inputs/Input.js b/src/cryptometrics/components/inputs/Input.js
index a079471..029202b 100644
--- a/src/cryptometrics/components/inputs/Input.js
+++ b/src/cryptometrics/components/inputs/Input.js
@@ -9,6 +9,7 @@ function Input({
   initialValue,
   symbolLeft,
   symbolRight,
+  id,
 }) {
   return (
     <span className="relative flex w-full flex-wrap items-stretch mb-3">
@@ -34,6 +35,7 @@ function Input({
         type={type ? type : "text"}
         onChange={onChange}
         defaultValue={initialValue || ""}
+        id={id ? id : undefined}
       ></input>
       {symbolRight && (
         <span className="absolute right-3 w-5 text-center items-center justify-center h-full z-10 py-3">
diff --git a/src/cryptometrics/components/radio/RadioForm.js b/src/cryptometrics/components/radio/RadioForm.js
index a6ab204..580bb19 100644
--- a/src/cryptometrics/components/radio/RadioForm.js
+++ b/src/cryptometrics/components/radio/RadioForm.js
@@ -35,6 +35,7 @@ function RadioInputForm({
                     symbolLeft={inputLeftSymbol}
                     symbolRight={inputRightSymbol}
                     type={inputType}
+                    id="radio-form-input"
                   />
                 )}
               </div>
diff --git a/src/cryptometrics/cypress/integration/home/filter.spec.js b/src/cryptometrics/cypress/integration/home/filter.spec.js
new file mode 100644
index 0000000..b1740b1
--- /dev/null
+++ b/src/cryptometrics/cypress/integration/home/filter.spec.js
@@ -0,0 +1,58 @@
+/// <reference types="cypress" />
+
+// FT-HP-4
+describe("filter on home page", () => {
+  beforeEach(() => {
+    cy.visit("localhost:3000");
+  });
+
+  it("filter price less than value", () => {
+    const filterButton = "#filter-button";
+    const priceOption = "#current_price-option";
+    cy.get(filterButton).should("be.visible");
+    cy.get(filterButton).click();
+    cy.get(priceOption).click();
+    cy.get("span").contains("is less than").click();
+    cy.get("#radio-form-input").type(100);
+    cy.get("button").contains("Filter").click();
+
+    cy.get("p#currency-price").each((price) => {
+      cy.wrap(price)
+        .invoke("text")
+        .then((price) => {
+          return price.replace("$", "").replace(",", "");
+        })
+        .then(parseFloat)
+        .should("be.lessThan", 100);
+    });
+  });
+
+  it("filter price greater than value", () => {
+    const filterButton = "#filter-button";
+    const priceOption = "#current_price-option";
+    cy.get(filterButton).should("be.visible");
+    cy.get(filterButton).click();
+    cy.get(priceOption).click();
+    cy.get("span").contains("is greater than").click();
+    cy.get("#radio-form-input").type(100);
+    cy.get("button").contains("Filter").click();
+
+    cy.get("p#currency-price").each((price) => {
+      cy.wrap(price)
+        .invoke("text")
+        .then((price) => {
+          return price.replace("$", "").replace(",", "");
+        })
+        .then(parseFloat)
+        .should("be.greaterThan", 100);
+    });
+  });
+
+  // it("search for invalid cryptocurrencies", () => {
+  //   const searchInput = "[placeholder='Search']";
+  //   const cryptocurrencyName = "abcd123";
+  //   cy.get(searchInput).should("be.visible");
+  //   cy.get(searchInput).type(`${cryptocurrencyName}`);
+  //   cy.get("body").should("contain", "No matching cryptocurrencies found.");
+  // });
+});
diff --git a/src/cryptometrics/cypress/integration/home/search.spec.js b/src/cryptometrics/cypress/integration/home/search.spec.js
new file mode 100644
index 0000000..ae69e62
--- /dev/null
+++ b/src/cryptometrics/cypress/integration/home/search.spec.js
@@ -0,0 +1,44 @@
+/// <reference types="cypress" />
+
+describe("search on home page", () => {
+  beforeEach(() => {
+    cy.visit("localhost:3000");
+  });
+  // FT-HP-2
+  it("search for valid cryptocurrencies", () => {
+    const searchInput = "[placeholder='Search']";
+    const cryptocurrencyName = "bitcoin";
+    cy.get(searchInput).should("be.visible");
+    cy.get(searchInput).type(`${cryptocurrencyName}`);
+
+    // card-view
+    cy.get("button#card-view").click();
+    cy.get("p#currency-name").each((name) => {
+      cy.wrap(name).should("contain", "Bitcoin");
+      cy.wrap(name).should("not.contain", "Ethereum");
+    });
+
+    // table-view
+    cy.get("button#list-view").click();
+    cy.get("p#currency-name").each((name) => {
+      cy.wrap(name).should("contain", "Bitcoin");
+      cy.wrap(name).should("not.contain", "Ethereum");
+    });
+  });
+
+  // FT-HP-3
+  it("search for invalid cryptocurrencies", () => {
+    const searchInput = "[placeholder='Search']";
+    const cryptocurrencyName = "abcd123";
+    cy.get(searchInput).should("be.visible");
+    cy.get(searchInput).type(`${cryptocurrencyName}`);
+
+    // card-view
+    cy.get("button#card-view").click();
+    cy.get("body").should("contain", "No matching cryptocurrencies found.");
+
+    // table-view
+    cy.get("button#list-view").click();
+    cy.get("body").should("contain", "No matching cryptocurrencies found.");
+  });
+});
diff --git a/src/cryptometrics/cypress/integration/home/table.spec.js b/src/cryptometrics/cypress/integration/home/table.spec.js
index 635f996..9b72364 100644
--- a/src/cryptometrics/cypress/integration/home/table.spec.js
+++ b/src/cryptometrics/cypress/integration/home/table.spec.js
@@ -4,7 +4,7 @@ describe("table on home page", () => {
   beforeEach(() => {
     cy.visit("localhost:3000");
   });
-
+  // FT-HP-1
   it("displays table", () => {
     cy.get("button#list-view").should("be.visible");
     cy.get("button#list-view").click();
diff --git a/src/cryptometrics/pages/index.js b/src/cryptometrics/pages/index.js
index 94c9839..ebb7959 100644
--- a/src/cryptometrics/pages/index.js
+++ b/src/cryptometrics/pages/index.js
@@ -126,7 +126,7 @@ export default function Home() {
                 content={<CollectionIcon className="w-6 h-6 dark:text-white" />}
               >
                 <div className="flex flex-wrap gap-x-10 gap-y-10 mt-3">
-                  {!listOfCoins.isLoading &&
+                  {!listOfCoins.isLoading && filteredCoins.length > 0 ? (
                     filteredCoins.map((coin) => {
                       return (
                         <CryptoChartCard
@@ -158,143 +158,166 @@ export default function Home() {
                           type="area"
                         />
                       );
-                    })}
+                    })
+                  ) : (
+                    <div className="text-2xl dark:text-white">
+                      No matching cryptocurrencies found.
+                    </div>
+                  )}
                 </div>
               </Tab>
               <Tab
                 id="list-view"
                 content={<TableIcon className="w-6 h-6 dark:text-white" />}
               >
-                <Table>
-                  {/* Table Header */}
-                  <TableHeader className="h-14 items-center sticky top-0 z-40">
-                    <TableCell className="w-6 h-10 text-center">Icon</TableCell>
-                    <TableCell className="w-24 h-10">
-                      <p className="font-medium text-base text-center">Name</p>
-                    </TableCell>
-                    <TableCell className="w-24 h-10">
-                      <p className="font-medium text-base text-center">Price</p>
-                    </TableCell>
-                    <TableCell className="w-[10%] h-10">
-                      <p className="font-medium text-base text-center">
-                        Market Cap
-                      </p>
-                    </TableCell>
-                    <TableCell className="w-40 h-10">
-                      <p className="font-medium text-base text-center">
-                        24h change in %
-                      </p>
-                    </TableCell>
-                    <TableCell className="w-40 h-10">
-                      <p className="font-medium text-base text-center">
-                        24h change in $
-                      </p>
-                    </TableCell>
-                    <TableCell className="h-10">
-                      <div className="w-52">
+                {filteredCoins?.length > 0 ? (
+                  <Table>
+                    {/* Table Header */}
+                    <TableHeader className="h-14 items-center sticky top-0 z-40">
+                      <TableCell className="w-6 h-10 text-center">
+                        Icon
+                      </TableCell>
+                      <TableCell className="w-24 h-10">
                         <p className="font-medium text-base text-center">
-                          Chart
+                          Name
                         </p>
-                      </div>
-                    </TableCell>
-                  </TableHeader>
-
-                  {/* Table Content */}
-                  {!listOfCoins.isLoading &&
-                    filteredCoins.map((coin, index) => {
-                      return (
-                        <Link
-                          key={"table_row_" + index}
-                          href={`/coins/${coin.id}`}
-                          passHref
-                        >
-                          <a>
-                            <TableRow>
-                              <TableCell className="w-6">
-                                <Image
-                                  src={coin.image}
-                                  width="32px"
-                                  height="32px"
-                                  alt={`${coin.id}_icon`}
-                                  layout="fixed"
-                                ></Image>
-                              </TableCell>
-                              <TableCell className="w-24">
-                                <p className="font-medium text-base text-center">
-                                  {coin.name}
-                                </p>
-                                <p className="font-light text-gray-300 text-sm mt-1">
-                                  {coin.symbol.toUpperCase()}
-                                </p>
-                              </TableCell>
-                              <TableCell className="w-24">
-                                <p className="font-light text-base text-blue-500 mt-1">
-                                  $
-                                  {numeral(coin.current_price).format(
-                                    "0,0.[0000000]"
-                                  )}
-                                </p>
-                              </TableCell>
-                              <TableCell className="w-[10%]">
-                                <p className="font-light text-base text-pink-400 mt-1">
-                                  $
-                                  {numeral(coin.market_cap).format(
-                                    "0,0.[000]a"
-                                  )}
-                                </p>
-                              </TableCell>
-                              <TableCell className="w-40">
-                                <p
-                                  className={classNames(
-                                    "font-light text-base mt-1",
-                                    {
-                                      "text-red-400":
-                                        coin.price_change_percentage_24h < 0,
-                                      "text-green-400":
-                                        coin.price_change_percentage_24h >= 0,
-                                    }
-                                  )}
-                                >
-                                  {numeral(
-                                    coin.price_change_percentage_24h
-                                  ).format("+0.0[00]")}
-                                  %
-                                </p>
-                              </TableCell>
-                              <TableCell className="w-40">
-                                <p
-                                  className={classNames(
-                                    "font-light text-base mt-1",
-                                    {
-                                      "text-red-400": coin.price_change_24h < 0,
-                                      "text-green-400":
-                                        coin.price_change_24h >= 0,
-                                    }
-                                  )}
-                                >
-                                  {numeral(coin.price_change_24h).format(
-                                    "$0,0.[0000]"
-                                  )}
-                                </p>
-                              </TableCell>
-                              <TableCell>
-                                <div className="h-[50px] w-52">
-                                  <CryptoRowLineChart
-                                    currencyId={coin.id}
-                                    color={
-                                      coin.price_change_24h >= 0
-                                        ? "#10B981"
-                                        : "#EF4444"
-                                    }
-                                  />
-                                </div>
-                              </TableCell>
-                            </TableRow>
-                          </a>
-                        </Link>
-                      );
-                    })}
-                </Table>
+                      </TableCell>
+                      <TableCell className="w-24 h-10">
+                        <p className="font-medium text-base text-center">
+                          Price
+                        </p>
+                      </TableCell>
+                      <TableCell className="w-[10%] h-10">
+                        <p className="font-medium text-base text-center">
+                          Market Cap
+                        </p>
+                      </TableCell>
+                      <TableCell className="w-40 h-10">
+                        <p className="font-medium text-base text-center">
+                          24h change in %
+                        </p>
+                      </TableCell>
+                      <TableCell className="w-40 h-10">
+                        <p className="font-medium text-base text-center">
+                          24h change in $
+                        </p>
+                      </TableCell>
+                      <TableCell className="h-10">
+                        <div className="w-52">
+                          <p className="font-medium text-base text-center">
+                            Chart
+                          </p>
+                        </div>
+                      </TableCell>
+                    </TableHeader>
+                    {/* Table Content */}
+                    {!listOfCoins.isLoading &&
+                      filteredCoins.map((coin, index) => {
+                        return (
+                          <Link
+                            key={"table_row_" + index}
+                            href={`/coins/${coin.id}`}
+                            passHref
+                          >
+                            <a>
+                              <TableRow>
+                                <TableCell className="w-6">
+                                  <Image
+                                    src={coin.image}
+                                    width="32px"
+                                    height="32px"
+                                    alt={`${coin.id}_icon`}
+                                    layout="fixed"
+                                  ></Image>
+                                </TableCell>
+                                <TableCell className="w-24">
+                                  <p
+                                    className="font-medium text-base text-center"
+                                    id="currency-name"
+                                  >
+                                    {coin.name}
+                                  </p>
+                                  <p
+                                    className="font-light text-gray-300 text-sm mt-1"
+                                    id="currency-symbol"
+                                  >
+                                    {coin.symbol.toUpperCase()}
+                                  </p>
+                                </TableCell>
+                                <TableCell className="w-24">
+                                  <p className="font-light text-base text-blue-500 mt-1">
+                                    $
+                                    {numeral(coin.current_price).format(
+                                      "0,0.[0000000]"
+                                    )}
+                                  </p>
+                                </TableCell>
+                                <TableCell className="w-[10%]">
+                                  <p className="font-light text-base text-pink-400 mt-1">
+                                    $
+                                    {numeral(coin.market_cap).format(
+                                      "0,0.[000]a"
+                                    )}
+                                  </p>
+                                </TableCell>
+                                <TableCell className="w-40">
+                                  <p
+                                    className={classNames(
+                                      "font-light text-base mt-1",
+                                      {
+                                        "text-red-400":
+                                          coin.price_change_percentage_24h < 0,
+                                        "text-green-400":
+                                          coin.price_change_percentage_24h >= 0,
+                                      }
+                                    )}
+                                  >
+                                    {numeral(
+                                      coin.price_change_percentage_24h
+                                    ).format("+0.0[00]")}
+                                    %
+                                  </p>
+                                </TableCell>
+                                <TableCell className="w-40">
+                                  <p
+                                    className={classNames(
+                                      "font-light text-base mt-1",
+                                      {
+                                        "text-red-400":
+                                          coin.price_change_24h < 0,
+                                        "text-green-400":
+                                          coin.price_change_24h >= 0,
+                                      }
+                                    )}
+                                  >
+                                    {numeral(coin.price_change_24h).format(
+                                      "$0,0.[0000]"
+                                    )}
+                                  </p>
+                                </TableCell>
+                                <TableCell>
+                                  <div className="h-[50px] w-52">
+                                    <CryptoRowLineChart
+                                      currencyId={coin.id}
+                                      color={
+                                        coin.price_change_24h >= 0
+                                          ? "#10B981"
+                                          : "#EF4444"
+                                      }
+                                    />
+                                  </div>
+                                </TableCell>
+                              </TableRow>
+                            </a>
+                          </Link>
+                        );
+                      })}
+                  </Table>
+                ) : (
+                  <div className="text-2xl mt-3 dark:text-white">
+                    No matching cryptocurrencies found.
+                  </div>
+                )}
               </Tab>
             </Tabs>
           </Container>
-- 
GitLab