Browse Source

[feat] Add E2E testing

Sergio Mattei 1 year ago
parent
commit
5a7212624d

+ 10
- 0
cypress.config.ts View File

1
+import { defineConfig } from "cypress";
2
+
3
+export default defineConfig({
4
+  e2e: {
5
+    baseUrl: "http://localhost:3001",
6
+    setupNodeEvents(on, config) {
7
+      // implement node event listeners here
8
+    },
9
+  },
10
+});

+ 2
- 0
cypress/e2e/eduardo.cy.ts View File

1
+// I will E2E test the article page.
2
+// User visits home -> User clicks on "laws or advice" -> List renders with 200

+ 2
- 0
cypress/e2e/eliam.cy.ts View File

1
+// I will E2E test the article page.
2
+// User visits home -> User clicks on "laws or advice" -> Article page contains the title

+ 50
- 0
cypress/e2e/sergio.cy.ts View File

1
+describe("Our app", () => {
2
+  beforeEach(() => {
3
+    cy.intercept("GET", "http://localhost:3000/api/getTopicList/*", {
4
+      fixture: "topics",
5
+    }).as("getTopicList");
6
+
7
+    cy.intercept("GET", "http://localhost:3000/api/getTopic/*", {
8
+      fixture: "article",
9
+    }).as("getTopic");
10
+
11
+    cy.viewport("iphone-x");
12
+    cy.visit("/");
13
+  });
14
+
15
+  it("shows the home page", () => {
16
+    cy.visit("/");
17
+    cy.contains("Bienvenidos");
18
+  });
19
+
20
+  it("shows a video in the home page", () => {
21
+    cy.visit("/");
22
+    cy.get("iframe").should("be.visible");
23
+  });
24
+
25
+  it("shows the about page", () => {
26
+    cy.visit("/about");
27
+    cy.contains("Renacer Social");
28
+  });
29
+
30
+  it("shows the individual service pages", () => {
31
+    cy.visit("/about");
32
+    cy.get(".item").first().click();
33
+    cy.contains("Casita de Paz");
34
+  });
35
+
36
+  it("shows the advice pages", () => {
37
+    cy.visit("/advice");
38
+    // Wait until the request to the intercept is completed.
39
+    cy.wait("@getTopicList");
40
+    cy.get(".item").first().click();
41
+    cy.wait("@getTopic");
42
+  });
43
+
44
+  it("allows exiting the individual service pages", () => {
45
+    cy.visit("/about");
46
+    cy.get(".item").first().click();
47
+    cy.get(".back-button-has-icon-only").first().click();
48
+    cy.contains("Servicios");
49
+  });
50
+});

+ 1643
- 0
cypress/fixtures/article.json
File diff suppressed because it is too large
View File


+ 14
- 0
cypress/fixtures/topics.json View File

1
+[
2
+  {
3
+    "blockId": "07ffbf26-babe-4c6a-b046-c7eb6d5c1a7f",
4
+    "name": "Pasa tiempo con tus hijos"
5
+  },
6
+  {
7
+    "blockId": "754d8ef3-14ae-4af6-a8c3-4ac4ede4d49d",
8
+    "name": "10 consejos para un matrimonio feliz"
9
+  },
10
+  {
11
+    "blockId": "d9fbaf7c-8f89-43b3-945c-927ed90e098b",
12
+    "name": "Busca ayuda si eres abusado/abusada"
13
+  }
14
+]

+ 37
- 0
cypress/support/commands.ts View File

1
+/// <reference types="cypress" />
2
+// ***********************************************
3
+// This example commands.ts shows you how to
4
+// create various custom commands and overwrite
5
+// existing commands.
6
+//
7
+// For more comprehensive examples of custom
8
+// commands please read more here:
9
+// https://on.cypress.io/custom-commands
10
+// ***********************************************
11
+//
12
+//
13
+// -- This is a parent command --
14
+// Cypress.Commands.add('login', (email, password) => { ... })
15
+//
16
+//
17
+// -- This is a child command --
18
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
19
+//
20
+//
21
+// -- This is a dual command --
22
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
23
+//
24
+//
25
+// -- This will overwrite an existing command --
26
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
27
+//
28
+// declare global {
29
+//   namespace Cypress {
30
+//     interface Chainable {
31
+//       login(email: string, password: string): Chainable<void>
32
+//       drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
33
+//       dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
34
+//       visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
35
+//     }
36
+//   }
37
+// }

+ 20
- 0
cypress/support/e2e.ts View File

1
+// ***********************************************************
2
+// This example support/e2e.ts is processed and
3
+// loaded automatically before your test files.
4
+//
5
+// This is a great place to put global configuration and
6
+// behavior that modifies Cypress.
7
+//
8
+// You can change the location of this file or turn off
9
+// automatically serving support files with the
10
+// 'supportFile' configuration option.
11
+//
12
+// You can read more here:
13
+// https://on.cypress.io/configuration
14
+// ***********************************************************
15
+
16
+// Import commands.js using ES2015 syntax:
17
+import "./commands";
18
+
19
+// Alternatively you can use CommonJS syntax:
20
+// require('./commands')

+ 1803
- 36
package-lock.json
File diff suppressed because it is too large
View File


+ 2
- 1
package.json View File

48
     "workbox-streams": "^5.1.4"
48
     "workbox-streams": "^5.1.4"
49
   },
49
   },
50
   "scripts": {
50
   "scripts": {
51
-    "start": "react-scripts start",
51
+    "start": "PORT=3001 react-scripts start",
52
     "build": "react-scripts build",
52
     "build": "react-scripts build",
53
     "test": "react-scripts test --transformIgnorePatterns 'node_modules/(?!(@ionic/react|@ionic/react-router|@ionic/core|@stencil/core|ionicons)/)'",
53
     "test": "react-scripts test --transformIgnorePatterns 'node_modules/(?!(@ionic/react|@ionic/react-router|@ionic/core|@stencil/core|ionicons)/)'",
54
     "eject": "react-scripts eject",
54
     "eject": "react-scripts eject",
76
     "@capacitor/cli": "4.4.0",
76
     "@capacitor/cli": "4.4.0",
77
     "@ionic/lab": "3.2.15",
77
     "@ionic/lab": "3.2.15",
78
     "@types/lodash": "^4.14.191",
78
     "@types/lodash": "^4.14.191",
79
+    "cypress": "^12.1.0",
79
     "husky": "^8.0.0",
80
     "husky": "^8.0.0",
80
     "pretty-quick": "^3.1.3"
81
     "pretty-quick": "^3.1.3"
81
   },
82
   },

+ 2
- 0
src/components/TopicList.tsx View File

32
   topics: Topic[];
32
   topics: Topic[];
33
   loading?: boolean;
33
   loading?: boolean;
34
 }> = ({ title, topics, loading }) => {
34
 }> = ({ title, topics, loading }) => {
35
+  console.log(topics);
35
   return (
36
   return (
36
     <IonList>
37
     <IonList>
37
       {title ? (
38
       {title ? (
43
       {loading && <ListSkeleton />}
44
       {loading && <ListSkeleton />}
44
 
45
 
45
       {!loading &&
46
       {!loading &&
47
+        topics &&
46
         topics.map((topic: Topic) => {
48
         topics.map((topic: Topic) => {
47
           return (
49
           return (
48
             <IonItem
50
             <IonItem

+ 36
- 27
src/pages/AboutListPage.tsx View File

1
 import {
1
 import {
2
   IonContent,
2
   IonContent,
3
   IonHeader,
3
   IonHeader,
4
+  IonImg,
4
   IonItem,
5
   IonItem,
6
+  IonLabel,
5
   IonList,
7
   IonList,
8
+  IonListHeader,
6
   IonPage,
9
   IonPage,
7
   IonTitle,
10
   IonTitle,
8
   IonToolbar,
11
   IonToolbar,
22
             <IonTitle size="large">About</IonTitle>
25
             <IonTitle size="large">About</IonTitle>
23
           </IonToolbar>
26
           </IonToolbar>
24
         </IonHeader>
27
         </IonHeader>
25
-        <div className="ion-padding">
28
+        <IonContent className="ion-padding">
29
+          <div className="video">
30
+            <iframe
31
+              src="https://www.youtube.com/embed/MRo8FR2l6VM"
32
+              title="YouTube video player"
33
+              allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
34
+            ></iframe>
35
+          </div>
26
           <h5>Bienvenidos</h5>
36
           <h5>Bienvenidos</h5>
27
           <p>
37
           <p>
28
-            Aqui tenemos una lista de las cosas que Renacer Social ofrece a la
29
-            sociedad.
38
+            Renacer Social ha iniciado una campaña de orientación a la comunidad
39
+            para que los niños y niñas puedan denunciar su situación de
40
+            maltrato. Con una seña discreta que consta de una “X” formada frente
41
+            al torso con los dedos índice, el menor puede dar alerta de su
42
+            situación de maltrato. Es responsabilidad de todos denunciar la
43
+            posible situación de maltrato si vemos a un menor realizar dicha
44
+            seña.
30
           </p>
45
           </p>
31
-        </div>
46
+          <IonList>
47
+            <IonListHeader>
48
+              <IonLabel>Servicios</IonLabel>
49
+            </IonListHeader>
50
+            <IonItem routerLink={`/services/casita`}>
51
+              <p className="ListItemText">Casita de Paz</p>
52
+            </IonItem>
53
+            <IonItem routerLink={`/services/Crecemos`}>
54
+              <p className="ListItemText">Crecemos</p>
55
+            </IonItem>
56
+            <IonItem routerLink={`/services/Lazos`}>
57
+              <p className="ListItemText">Proyecto Lazos</p>
58
+            </IonItem>
59
+            <IonItem routerLink={`/services/Supervisadas`}>
60
+              <p className="ListItemText">Visitas Supervisadas</p>
61
+            </IonItem>
62
+          </IonList>
63
+        </IonContent>
32
       </IonContent>
64
       </IonContent>
33
-      <IonList>
34
-        <IonItem routerLink={`/services/casita`}>
35
-          <p className="ListItemText">Casita de Paz</p>
36
-        </IonItem>
37
-      </IonList>
38
-
39
-      <IonList>
40
-        <IonItem routerLink={`/services/Crecemos`}>
41
-          <p className="ListItemText">Crecemos</p>
42
-        </IonItem>
43
-      </IonList>
44
-
45
-      <IonList>
46
-        <IonItem routerLink={`/services/Lazos`}>
47
-          <p className="ListItemText">Proyecto Lazos</p>
48
-        </IonItem>
49
-      </IonList>
50
-
51
-      <IonList>
52
-        <IonItem routerLink={`/services/Supervisadas`}>
53
-          <p className="ListItemText">Visitas Supervisadas</p>
54
-        </IonItem>
55
-      </IonList>
56
     </IonPage>
65
     </IonPage>
57
   );
66
   );
58
 };
67
 };

+ 3
- 3
src/pages/AdviceListPage.tsx View File

14
 
14
 
15
 const AdviceListPage: React.FC = () => {
15
 const AdviceListPage: React.FC = () => {
16
   const { data: paternidad, error: paternidadError } = useSWR<Topic[]>(
16
   const { data: paternidad, error: paternidadError } = useSWR<Topic[]>(
17
-    "/api/getTopicList?type=advice&category=Paternidad",
17
+    "/api/getTopicList/?type=advice&category=Paternidad",
18
     fetcher
18
     fetcher
19
   );
19
   );
20
   const { data: matrimonio, error: matrimonioError } = useSWR<Topic[]>(
20
   const { data: matrimonio, error: matrimonioError } = useSWR<Topic[]>(
21
-    "/api/getTopicList?type=advice&category=Matrimonio",
21
+    "/api/getTopicList/?type=advice&category=Matrimonio",
22
     fetcher
22
     fetcher
23
   );
23
   );
24
   const { data: abuso, error: abusoError } = useSWR<Topic[]>(
24
   const { data: abuso, error: abusoError } = useSWR<Topic[]>(
25
-    "/api/getTopicList?type=advice&category=Abuso%20Sexual",
25
+    "/api/getTopicList/?type=advice&category=Abuso%20Sexual",
26
     fetcher
26
     fetcher
27
   );
27
   );
28
   const error = paternidadError || matrimonioError || abusoError;
28
   const error = paternidadError || matrimonioError || abusoError;

+ 1
- 1
src/pages/ArticlePage.tsx View File

23
   match,
23
   match,
24
 }) => {
24
 }) => {
25
   const { data, error } = useSWR<any>(
25
   const { data, error } = useSWR<any>(
26
-    `/api/getTopic?id=${match.params.articleId}`,
26
+    `/api/getTopic/?id=${match.params.articleId}`,
27
     fetcher
27
     fetcher
28
   );
28
   );
29
   const isLoading = !data && !error;
29
   const isLoading = !data && !error;

+ 15
- 1
src/pages/Home.tsx View File

21
           </IonToolbar>
21
           </IonToolbar>
22
         </IonHeader>
22
         </IonHeader>
23
         <div className="ion-padding">
23
         <div className="ion-padding">
24
-          <h5>Bienvenidos</h5>
24
+          <div className="video">
25
+            <iframe
26
+              src="https://www.youtube.com/embed/xCtgekNpxI4"
27
+              title="YouTube video player"
28
+              allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
29
+            ></iframe>
30
+          </div>
31
+          <h2>Bienvenidos</h2>
25
           <p>
32
           <p>
26
             Somos una organización Lorem Ipsum is simply dummy text of the
33
             Somos una organización Lorem Ipsum is simply dummy text of the
27
             printing and typesetting industry. Lorem Ipsum.
34
             printing and typesetting industry. Lorem Ipsum.
28
           </p>
35
           </p>
36
+
37
+          <h3>Si se encuentra en peligro llame al 9-1-1 o al 787-343-2020</h3>
38
+          <p>
39
+            Si usted se encuentra en peligro inminente, llame a la Policía de
40
+            Puerto Rico al 9-1-1 o al 787-343-2020. Debe buscar protección para
41
+            usted y los suyos de manera inmediata. NO ESPERE.
42
+          </p>
29
         </div>
43
         </div>
30
       </IonContent>
44
       </IonContent>
31
     </IonPage>
45
     </IonPage>

+ 0
- 1
src/pages/LawListPage.tsx View File

1
 import {
1
 import {
2
   IonContent,
2
   IonContent,
3
   IonHeader,
3
   IonHeader,
4
-  IonLoading,
5
   IonPage,
4
   IonPage,
6
   IonTitle,
5
   IonTitle,
7
   IonToast,
6
   IonToast,

+ 18
- 0
src/theme/global.css View File

17
 .notion-blank {
17
 .notion-blank {
18
   display: none !important;
18
   display: none !important;
19
 }
19
 }
20
+
21
+.video {
22
+  position: relative;
23
+  overflow: hidden;
24
+  width: 100%;
25
+  padding-top: 56.25%; /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
26
+}
27
+
28
+/* Then style the iframe to fit in the container div with full height and width */
29
+.video iframe {
30
+  position: absolute;
31
+  top: 0;
32
+  left: 0;
33
+  bottom: 0;
34
+  right: 0;
35
+  width: 100%;
36
+  height: 100%;
37
+}