diff --git a/README.md b/README.md index 01068945..cec15078 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,299 @@ -# helpafamily.margaritahumanitarian.org +# CES REPORT +## The issue -Impactful ways to help families in need through donated meals, hygiene kits, and more. +This issue is trying to obtain [a code coverage of 80%](https://github.com/margaritahumanitarian/helpafamily/issues/367) on the [helpafamily.margaritahumanitarian.org](https://helpafamily.margaritahumanitarian.org/) project code. The Margarita Humanitarian Foundation is a 501c3 nonprofit public charity located in Palmdale, California (USA) that provides free assistance for people in need. They offer many services such as youth mentorship, health, career, and education workshops and training so the less fortunate can get access to social services, healthcare, food, and more aid in the golden state. Its mission is to develop high-impact ways to help underserved and marginalized groups. Their portfolio contains some programs in the Antelope Valley region and globally. They help families who need help the most, addressing the whole family's needs, from youths to elders, always with kindness and love. +It is possible to learn more about the project on the [website](https://www.margaritahumanitarian.org/). -This repo contains the code behind [helpafamily.margaritahumanitarian.org](https://helpafamily.margaritahumanitarian.org/). While the short-term goal is to provide ways for donors to help families in the Antelope Valley, the long-term goal is to help families in need at a global scale through international volunteers and partnering humanitarian organizations around the world. +### How alive is the project? -Learn more about [Margarita Humanitarian Foundation](https://www.margaritahumanitarian.org/). +The project started in July of 2021. In the early stages of development, it has seen an early spike in activity. However, now it shows signs of a gradual [fade out](https://github.com/margaritahumanitarian/helpafamily/graphs/contributors) (as of the writing of this report). The project has 54 stars on GitHub and a community of 59 contributors. It also has 20 open issues and roughly 124 closed ones, with 95 forks. Despite not being a massive project, the authors of this report considered it an exciting project, and it is a way to help others in need using our skillset and field of study. -## Contributing and installation +![Commit contributions](https://user-images.githubusercontent.com/44166746/168834968-bcd298c5-a440-40f8-ae39-92853503c1e3.png) -If you would like to help us with this project you can learn more from our [Help-a-Family Manual](https://margaritahumanitarian.gitbook.io/help-a-family-manual/) and our [CONTRIBUTING](CONTRIBUTING.md) file. +### How important is it? -## Community +There are undeniable advantages to testing software products; therefore, the authors will not enumerate them here. At the time of the fork, the project only contained a few set tests. The main goal of the issue is to get to 80% code coverage, so we developed one main **task plan** and a **test plan** - in this section, we will primarily focus on the task plan since the authors of this report will address the test plan later on. We will start by implementing end-to-end tests with Selenium IDE and Jest. This setup allows us to test the main features of the web application - so we can maximize the test coverage with the time constraints that we have. In the second stage of the testing project, we intend to start to test the main modules of the project in order of criticality - also to prevent an invisible path problem situation. We aim to help the Margarita Humanitarian Foundation provide its user base with a web application that guarantees no failure with this approach, so they can continue to help their community. -Our community is made up of people from all over the world, so times when people -are active online vary. +### What is it good for? -Come say hi in: +The main goal of this project is to provide ways for donors to help families in the Antelope Valley via an easy-to-use web application that allows them to make donations and contact some partners. -- Our [#help-a-family Discord server](https://discord.gg/WsmqrcGqyE) +### What are the technologies involved? -We're still getting this started, so be patient and hang around if no one's there. -Soon it'll get more active. - -## How It Works - -This project uses: +The project's technology stack consists of React, Next.js, Tailwind CSS, and daisyUI Tailwind CSS Components. However, we used [Selenium.js](https://www.selenium.dev) with [Jest](https://jestjs.io) for the test framework to perform end-to-end test of the application on Chrome. For package managers, the project used NPM and Yarn. +In conclusion, this project uses: - [React](https://reactjs.org/) - [Next.js](https://nextjs.org/docs/) - [Tailwind CSS](https://tailwindcss.com/docs) - [daisyUI Tailwind CSS Components](https://daisyui.com/) +- [Jest](https://jestjs.io) +- [Selenium.js](https://www.selenium.dev) + +### Is the project in a development phase or maintenance/evolution phase? + +We assume that the project is still in the development stage - because the main contributors did not yet implement some modules, and there are still some open issues. But, the number of commits is declining. So we assume that the project is in the development phase, but it is slowing down - a common issue with open-source projects, sometimes, they can freeze for a while. + +### Community + +The core contributors also have a [Discord server](https://discord.gg/WsmqrcGqyE) with some community members. However, there are two disclaimers. The first disclaimer is that the community is made up of people worldwide, so there is no standard timetable on which the community is online. The second disclaimer is that they are *"getting started,"* so it is expected not to exist as much activity on the server. + +## Requirements +## Design +### Test plan + +One of the best forms of test documentation there is the test plan. We used a variation of the IBM test plan model. According to the IBM documentation, the test plan describes the scope of the overall test effort and provides a record of the test planning process. Typically, a test plan identifies requirements, risks, test cases, the test environments, business and quality objectives, test schedules, and other items. However, the test plan had to have some adaptations to enable the application of restrictions imposed by the nature of the language and project. + +The test plan consists of six columns - Scenario, Steps, Tester Name, Approval Criteria, Actual result, and Final result. The Scenario, Tester Name, Approval Criteria, Actual, and Final results attributes are self-explanatory, but the attribute *"Steps"* come from BDD. The Steps attributes must contain a sequence of steps that allows us to conduct a test on the webpage. For example, *"Open the browser," "click on ...," "Fill in the payment form,"* and other actions that combined make an acceptance test. + +Another essential detail is that these tests were tailored-made for a computer (MacOs) with the web browser Chrome. It is possible to conduct these tests on Firefox, Safari, Opera, and other significant browsers, OSs, and devices, however, we did not perform them due to time and infrastructure limitations. To do so we needed to use a Selenium Grid and create some system configurations, for example, a Linux PC with Firefox, a Windows PC with Microsoft Edge, a iPhone with Chrome. Some of this enviorments need payed liceses. Configur and allocate this network would cost valuable time and (maybe) monetary resources, defeating the purpose of the curriculum unit. In the future, if the charity association picks up and requires more "heavy-weight" tests to ensure a higher level of code quality, it is possible to assemble such infrastructure at some expense - time and resources manly. It is possible to find the test plan on the following [link](https://1drv.ms/x/s!AlSqQ8H6UyqqmfoxHBitd6JypCfwuw?e=OIHu26). + +### Source code files +The main source code files to fixe these issues are the following: + +![Issue code files](https://user-images.githubusercontent.com/44166746/168874151-67eaa8a3-809d-4f3d-ba20-5f72e752b743.png) + +Note: Some dependencies needed to be added; that is why the package.json and yarn.lock files were also altered. + +### Fix source code + +We developed the test scripts with the help of Selenium IDE. The IDE allows us to perform capture and replay tests and then export the tests into JavaScript. However, the process is not as straightforward as it might first appear. After exporting the scripts, we needed to adjust the functions that find the web page elements. It is a common issue with Selenium. Selenium sometimes does not see the web page elements, especially if they are inside a combo box. Therefore, we need to search each element of the web page manually and find its exact location so that Selenium can see it. Another issue that we had during the development of the test scripts is that these tests run at CPU speeds. So they do not encompass the time that it takes for a web page to load or the time that a user takes when clicking on some element. Therefore, we adjusted the speed at which the tests run so they could wait for pages to load or for monetary transactions to take place. One final note that it is essential to mention is that the project had a *pretty* file built-in that obligated developers to follow a standard way to code. This configuration helps ensure the standardization of the contributions and provides quality standards across the project. Another aspect to consider when writing these tests is the configuration of the test environment — one of the reasons we had some initial problems when implementing the issue. We needed to align the Chrome version of our machines to the Chrome (web-driver) of the Selenium IDE; otherwise, it would not run. The readers can observe a test file below: +``` javascript +// Porto, 2022 +// This code was made with love by Francisco Bastos (https://www.linkedin.com/in/francisco-bastos-031369160/) +// for the curriculum unit of Comprehension and Evolution of Software at the +// master's in Software Engineering at the Faculty of Engineering of the University of Porto. +// Feel free to contact the author if any questions arise. +// +import { Builder, By, until } from 'selenium-webdriver'; +import assert from 'assert'; + +describe('Make a donation', function () { + jest.setTimeout(60000); + let driver; + // eslint-disable-next-line no-unused-vars + let vars; + beforeEach(async function () { + driver = await new Builder().forBrowser('chrome').build(); + vars = {}; + }); + afterEach(async function () { + await driver.quit(); + }); + it('Make a donation', async function () { + // Test name: Make a donation + // Step # | name | target | value + // 1 | open | / | + await driver.get('http://localhost:3000/'); + // 2 | setWindowSize | 1920x1080 | + await driver.manage().window().setRect({ width: 1920, height: 1080 }); + // 3 | click | xpath=//input | + await driver.findElement(By.xpath('//input')).click(); + // 4 | click | xpath=//label[contains(.,'People of Color in Need')] | + await driver + .findElement(By.xpath("//label[contains(.,'People of Color in Need')]")) + .click(); + // 5 | click | xpath=//label[contains(.,'Immigrants in Need')] | + await driver + .findElement(By.xpath("//label[contains(.,'Immigrants in Need')]")) + .click(); + // 6 | click | xpath=//label[contains(.,'Seniors in Need')] | + await driver + .findElement(By.xpath("//label[contains(.,'Seniors in Need')]")) + .click(); + // Apply timeout for 10 seconds + await driver.manage().setTimeouts({ implicit: 10000 }); + // 7 | click | xpath=//select | + await driver.findElement(By.xpath('//select')).click(); + // 8 | select | css=#amount and xpath=//option[. = '$5'] | label=$5 + { + const dropdown = await driver.findElement(By.css('#amount')); + await dropdown.findElement(By.xpath("//option[. = '$5']")).click(); + } + // 9 | click | xpath=//form/div/button[2] | + await driver.findElement(By.xpath('//form/div/button[2]')).click(); + // 10 | click | xpath=//input[@id='email'] | + await driver.findElement(By.xpath("//input[@id='email']")).click(); + // 11 | type | xpath=//input[@id='email'] | francisco@gmail.com + await driver + .findElement(By.xpath("//input[@id='email']")) + .sendKeys('francisco@gmail.com'); + // 12 | click | xpath=//div[@id='cardNumber-fieldset']/div/div/div/span/input | + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div/div/div/span/input") + ) + .click(); + // 13 | type | xpath=//fieldset/div/div/div/div/span/input | 6011 1111 1111 1117 + await driver + .findElement(By.xpath('//fieldset/div/div/div/div/span/input')) + .sendKeys('6011 1111 1111 1117'); + // 14 | type | xpath=//div[@id='cardNumber-fieldset']/div[2]/div/div/span/input | 11 / 26 + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div[2]/div/div/span/input") + ) + .sendKeys('11 / 26'); + // 15 | type | xpath=//div[@id='cardNumber-fieldset']/div[3]/div/div/span/input | 123 + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div[3]/div/div/span/input") + ) + .sendKeys('123'); + // 16 | type | xpath=//div[3]/div/div/div/div/div[2]/div/div/div/div/span/input | Francisco + await driver + .findElement( + By.xpath('//div[3]/div/div/div/div/div[2]/div/div/div/div/span/input') + ) + .sendKeys('Francisco'); + // 17 | click | xpath=//div[3]/div/div/span/input | + await driver.findElement(By.xpath('//div[3]/div/div/span/input')).click(); + // 18 | click | xpath=//div[@id='root']/div/div/div[2]/div/div[2]/form/div[2]/div[2]/button/div[3] | + await driver + .findElement( + By.xpath( + "//div[@id='root']/div/div/div[2]/div/div[2]/form/div[2]/div[2]/button/div[3]" + ) + ) + .click(); + // 19 | waitForElementPresent | xpath=//h1[contains(.,'Thank You!')] | 60000 + await driver.wait( + until.elementLocated(By.xpath("//h1[contains(.,'Thank You!')]")), + 60000 + ); + // 20 | assertText | //*[@id="__next"]/html/body/div/div[1]/div/div/h1 | Thank You! + assert( + (await driver + .findElement( + By.xpath('//*[@id="__next"]/html/body/div/div[1]/div/div/h1') + ) + .getText()) == 'Thank You!' + ); + }); +}); +``` +This test file portrays the test "Make a donation," and it is pretty simple to read (one of the advantages of Selenium IDE). +In the following section, we create the test environment. We extend the test timeout to roughly 16.(6)h, so the test has time to execute. Then we initialize and create the Chrome Driver and set the behavior for after the test - quit and close the browser: +```javascript +jest.setTimeout(60000); + let driver; + // eslint-disable-next-line no-unused-vars + let vars; + beforeEach(async function () { + driver = await new Builder().forBrowser('chrome').build(); + vars = {}; + }); + afterEach(async function () { + await driver.quit(); + }); +``` + +Now we access the web page and then start the search for each element of the web page filling in every form and simulating a typical user flow. +``` javascript +it('Make a donation', async function () { + // Test name: Make a donation + // Step # | name | target | value + // 1 | open | / | + await driver.get('http://localhost:3000/'); + // 2 | setWindowSize | 1920x1080 | + await driver.manage().window().setRect({ width: 1920, height: 1080 }); + // 3 | click | xpath=//input | + await driver.findElement(By.xpath('//input')).click(); + // 4 | click | xpath=//label[contains(.,'People of Color in Need')] | + await driver + .findElement(By.xpath("//label[contains(.,'People of Color in Need')]")) + .click(); + // 5 | click | xpath=//label[contains(.,'Immigrants in Need')] | + await driver + .findElement(By.xpath("//label[contains(.,'Immigrants in Need')]")) + .click(); + // 6 | click | xpath=//label[contains(.,'Seniors in Need')] | + await driver + .findElement(By.xpath("//label[contains(.,'Seniors in Need')]")) + .click(); + // Apply timeout for 10 seconds + await driver.manage().setTimeouts({ implicit: 10000 }); + // 7 | click | xpath=//select | + await driver.findElement(By.xpath('//select')).click(); + // 8 | select | css=#amount and xpath=//option[. = '$5'] | label=$5 + { + const dropdown = await driver.findElement(By.css('#amount')); + await dropdown.findElement(By.xpath("//option[. = '$5']")).click(); + } + // 9 | click | xpath=//form/div/button[2] | + await driver.findElement(By.xpath('//form/div/button[2]')).click(); + // 10 | click | xpath=//input[@id='email'] | + await driver.findElement(By.xpath("//input[@id='email']")).click(); + // 11 | type | xpath=//input[@id='email'] | francisco@gmail.com + await driver + .findElement(By.xpath("//input[@id='email']")) + .sendKeys('francisco@gmail.com'); + // 12 | click | xpath=//div[@id='cardNumber-fieldset']/div/div/div/span/input | + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div/div/div/span/input") + ) + .click(); + // 13 | type | xpath=//fieldset/div/div/div/div/span/input | 6011 1111 1111 1117 + await driver + .findElement(By.xpath('//fieldset/div/div/div/div/span/input')) + .sendKeys('6011 1111 1111 1117'); + // 14 | type | xpath=//div[@id='cardNumber-fieldset']/div[2]/div/div/span/input | 11 / 26 + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div[2]/div/div/span/input") + ) + .sendKeys('11 / 26'); + // 15 | type | xpath=//div[@id='cardNumber-fieldset']/div[3]/div/div/span/input | 123 + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div[3]/div/div/span/input") + ) + .sendKeys('123'); + // 16 | type | xpath=//div[3]/div/div/div/div/div[2]/div/div/div/div/span/input | Francisco + await driver + .findElement( + By.xpath('//div[3]/div/div/div/div/div[2]/div/div/div/div/span/input') + ) + .sendKeys('Francisco'); + // 17 | click | xpath=//div[3]/div/div/span/input | + await driver.findElement(By.xpath('//div[3]/div/div/span/input')).click(); + // 18 | click | xpath=//div[@id='root']/div/div/div[2]/div/div[2]/form/div[2]/div[2]/button/div[3] | + await driver + .findElement( + By.xpath( + "//div[@id='root']/div/div/div[2]/div/div[2]/form/div[2]/div[2]/button/div[3]" + ) + ) + .click(); +``` + +The following instructions show that we need to extend the time for the test to run even for specific actions. We rose the timeout again for 60000 seconds. +```javascript +// 19 | waitForElementPresent | xpath=//h1[contains(.,'Thank You!')] | 60000 + await driver.wait( + until.elementLocated(By.xpath("//h1[contains(.,'Thank You!')]")), + 60000 + ); +``` + +Now we test the web page and try to assert the web page's content with the message "Thank You!" which means that a donation was correctly made. +```javascript +// 20 | assertText | //*[@id="__next"]/html/body/div/div[1]/div/div/h1 | Thank You! + assert( + (await driver + .findElement( + By.xpath('//*[@id="__next"]/html/body/div/div[1]/div/div/h1') + ) + .getText()) == 'Thank You!' + ); +``` + +The remaining tests follow a structure very similar to this one. + +## Submit the fix + +We submitted a pull request to the project's GitHub, which the reader can find [here](https://github.com/margaritahumanitarian/helpafamily/pull/373). At the time of the writing of this report, it has not been yet approved and merged - maybe due to the recent inactivity of the main contributors; however, we hope it will be soon because we think that it is an excellent contribution to the project. ## Contributors diff --git a/__tests__/E2E/email.spec.js b/__tests__/E2E/email.spec.js new file mode 100644 index 00000000..cc72cd96 --- /dev/null +++ b/__tests__/E2E/email.spec.js @@ -0,0 +1,39 @@ +// Porto, 2022 +// This code was made with love by Ana Rita +// for the curriculum unit of Comprehension and Evolution of Software at the +// master's in Software Engineering at the Faculty of Engineering of the University of Porto. +// Feel free to contact the author if any questions arise. +// +const { Builder, By } = require('selenium-webdriver'); +const assert = require('assert'); + +describe('email', function () { + jest.setTimeout(30000); + let driver; + // eslint-disable-next-line no-unused-vars + let vars; + beforeEach(async function () { + driver = await new Builder().forBrowser('chrome').build(); + vars = {}; + }); + afterEach(async function () { + await driver.quit(); + }); + it('email', async function () { + // Test name: email + // Step # | name | target | value + // 1 | open | / | + await driver.get('http://localhost:3000/'); + // 2 | setWindowSize | 1792x1016 | + await driver.manage().window().setRect({ width: 1792, height: 1016 }); + // 3 | click | linkText=Give Your Time | + await driver.findElement(By.linkText('Give Your Time')).click(); + // 4 | click | css=.btn:nth-child(1) | + await driver.findElement(By.css('.btn:nth-child(1)')).click(); + // 5 | assertText | css=.btn:nth-child(1) | Donate + assert( + (await driver.findElement(By.css('.btn:nth-child(1)')).getText()) == + 'Donate' + ); + }); +}); diff --git a/__tests__/E2E/hotmealdonate.spec.js b/__tests__/E2E/hotmealdonate.spec.js new file mode 100644 index 00000000..305a9515 --- /dev/null +++ b/__tests__/E2E/hotmealdonate.spec.js @@ -0,0 +1,102 @@ +// Porto, 2022 +// This code was made with love by Francisco Bastos (https://www.linkedin.com/in/francisco-bastos-031369160/) +// for the curriculum unit of Comprehension and Evolution of Software at the +// master's in Software Engineering at the Faculty of Engineering of the University of Porto. +// Feel free to contact the author if any questions arise. +// +import { Builder, By, until } from 'selenium-webdriver'; +import assert from 'assert'; + +describe('Hot meal donate', function () { + var webdriver = require('selenium-webdriver'); + + var driver = new webdriver.Builder() + .withCapabilities(webdriver.Capabilities.chrome()) + .build(); + + jest.setTimeout(60000); + // eslint-disable-next-line no-unused-vars + let vars; + beforeEach(async function () { + driver = await new Builder().forBrowser('chrome').build(); + vars = {}; + }); + afterEach(async function () { + await driver.quit(); + }); + it('Hot meal donate', async function () { + // Test name: Hot meal donate + // Step # | name | target | value + // 1 | open | / | + await driver.get('http://localhost:3000/'); + // 2 | setWindowSize | 1920x1080 | + await driver.manage().window().setRect({ width: 1920, height: 1080 }); + // 3 | click | xpath=//div[@id='__next']/div/main/div[2]/div/div/div/div/div/div/button | + await driver + .findElement( + By.xpath( + "//div[@id='__next']/div/main/div[2]/div/div/div/div/div/div/button" + ) + ) + .click(); + // Apply timeout for 10 seconds + await driver.manage().setTimeouts({ implicit: 10000 }); + // 4 | click | xpath=//div[@id='email-fieldset']/div/div/div/div/span/input | + await driver + .findElement( + By.xpath("//div[@id='email-fieldset']/div/div/div/div/span/input") + ) + .click(); + // 5 | type | xpath=//div[@id='email-fieldset']/div/div/div/div/span/input | francisco@gmail.com + await driver + .findElement( + By.xpath("//div[@id='email-fieldset']/div/div/div/div/span/input") + ) + .sendKeys('francisco@gmail.com'); + // 6 | click | xpath=//div[@id='cardNumber-fieldset']/div/div/div/span/input | + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div/div/div/span/input") + ) + .click(); + // 7 | type | xpath=//fieldset/div/div/div/div/span/input | 6011 1111 1111 1117 + await driver + .findElement(By.xpath('//fieldset/div/div/div/div/span/input')) + .sendKeys('6011 1111 1111 1117'); + // 8 | type | xpath=//div[2]/div/div/span/input | 11 / 26 + await driver + .findElement(By.xpath('//div[2]/div/div/span/input')) + .sendKeys('11 / 26'); + // 9 | type | xpath=//div[@id='billingName-fieldset']/div/div/div/span/input | Francisco + await driver + .findElement( + By.xpath("//div[@id='billingName-fieldset']/div/div/div/span/input") + ) + .sendKeys('Francisco'); + // 10 | click | xpath=//div[@id='cardNumber-fieldset']/div[3]/div/div/span/input | + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div[3]/div/div/span/input") + ) + .click(); + // 11 | type | xpath=//div[3]/div/div/span/input | 123 + await driver + .findElement(By.xpath('//div[3]/div/div/span/input')) + .sendKeys('123'); + // 12 | click | xpath=//button/div[3] | + await driver.findElement(By.xpath('//button/div[3]')).click(); + // 13 | waitForElementPresent | xpath=//h1[contains(.,'Thank You!')] | 60000 + await driver.wait( + until.elementLocated(By.xpath("//h1[contains(.,'Thank You!')]")), + 60000 + ); + // 14 | assertText | //*[@id="__next"]/html/body/div/div[1]/div/div/h1 | Thank You! + assert( + (await driver + .findElement( + By.xpath('//*[@id="__next"]/html/body/div/div[1]/div/div/h1') + ) + .getText()) == 'Thank You!' + ); + }); +}); diff --git a/__tests__/E2E/hotmeallearnmore.spec.js b/__tests__/E2E/hotmeallearnmore.spec.js new file mode 100644 index 00000000..db1d70b9 --- /dev/null +++ b/__tests__/E2E/hotmeallearnmore.spec.js @@ -0,0 +1,39 @@ +// Porto, 2022 +// This code was made with love by Francisco Bastos (https://www.linkedin.com/in/francisco-bastos-031369160/) +// for the curriculum unit of Comprehension and Evolution of Software at the +// master's in Software Engineering at the Faculty of Engineering of the University of Porto. +// Feel free to contact the author if any questions arise. +// +import { Builder, By } from 'selenium-webdriver'; +import assert from 'assert'; + +describe('Hot meal learn more', function () { + jest.setTimeout(60000); + let driver; + // eslint-disable-next-line no-unused-vars + let vars; + beforeEach(async function () { + driver = await new Builder().forBrowser('chrome').build(); + vars = {}; + }); + afterEach(async function () { + await driver.quit(); + }); + it('Hot meal learn more', async function () { + // Test name: Hot meal learn more + // Step # | name | target | value + // 1 | open | / | + await driver.get('http://localhost:3000/'); + // 2 | setWindowSize | 1920x1080 | + await driver.manage().window().setRect({ width: 1920, height: 1080 }); + // 3 | click | xpath=//button[contains(.,'Learn More')] | + await driver + .findElement(By.xpath("//button[contains(.,'Learn More')]")) + .click(); + // 4 | assertText | xpath=//h1/div | Free Food Boxes for Hungry Families. Every Saturday! + assert( + (await driver.findElement(By.xpath('//h1/div')).getText()) == + 'Free Food Boxes for Hungry Families. Every Saturday!' + ); + }); +}); diff --git a/__tests__/E2E/makeadonation.spec.js b/__tests__/E2E/makeadonation.spec.js new file mode 100644 index 00000000..6919cab9 --- /dev/null +++ b/__tests__/E2E/makeadonation.spec.js @@ -0,0 +1,112 @@ +// Porto, 2022 +// This code was made with love by Francisco Bastos (https://www.linkedin.com/in/francisco-bastos-031369160/) +// for the curriculum unit of Comprehension and Evolution of Software at the +// master's in Software Engineering at the Faculty of Engineering of the University of Porto. +// Feel free to contact the author if any questions arise. +// +import { Builder, By, until } from 'selenium-webdriver'; +import assert from 'assert'; + +describe('Make a donation', function () { + jest.setTimeout(60000); + let driver; + // eslint-disable-next-line no-unused-vars + let vars; + beforeEach(async function () { + driver = await new Builder().forBrowser('chrome').build(); + vars = {}; + }); + afterEach(async function () { + await driver.quit(); + }); + it('Make a donation', async function () { + // Test name: Make a donation + // Step # | name | target | value + // 1 | open | / | + await driver.get('http://localhost:3000/'); + // 2 | setWindowSize | 1920x1080 | + await driver.manage().window().setRect({ width: 1920, height: 1080 }); + // 3 | click | xpath=//input | + await driver.findElement(By.xpath('//input')).click(); + // 4 | click | xpath=//label[contains(.,'People of Color in Need')] | + await driver + .findElement(By.xpath("//label[contains(.,'People of Color in Need')]")) + .click(); + // 5 | click | xpath=//label[contains(.,'Immigrants in Need')] | + await driver + .findElement(By.xpath("//label[contains(.,'Immigrants in Need')]")) + .click(); + // 6 | click | xpath=//label[contains(.,'Seniors in Need')] | + await driver + .findElement(By.xpath("//label[contains(.,'Seniors in Need')]")) + .click(); + // Apply timeout for 10 seconds + await driver.manage().setTimeouts({ implicit: 10000 }); + // 7 | click | xpath=//select | + await driver.findElement(By.xpath('//select')).click(); + // 8 | select | css=#amount and xpath=//option[. = '$5'] | label=$5 + { + const dropdown = await driver.findElement(By.css('#amount')); + await dropdown.findElement(By.xpath("//option[. = '$5']")).click(); + } + // 9 | click | xpath=//form/div/button[2] | + await driver.findElement(By.xpath('//form/div/button[2]')).click(); + // 10 | click | xpath=//input[@id='email'] | + await driver.findElement(By.xpath("//input[@id='email']")).click(); + // 11 | type | xpath=//input[@id='email'] | francisco@gmail.com + await driver + .findElement(By.xpath("//input[@id='email']")) + .sendKeys('francisco@gmail.com'); + // 12 | click | xpath=//div[@id='cardNumber-fieldset']/div/div/div/span/input | + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div/div/div/span/input") + ) + .click(); + // 13 | type | xpath=//fieldset/div/div/div/div/span/input | 6011 1111 1111 1117 + await driver + .findElement(By.xpath('//fieldset/div/div/div/div/span/input')) + .sendKeys('6011 1111 1111 1117'); + // 14 | type | xpath=//div[@id='cardNumber-fieldset']/div[2]/div/div/span/input | 11 / 26 + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div[2]/div/div/span/input") + ) + .sendKeys('11 / 26'); + // 15 | type | xpath=//div[@id='cardNumber-fieldset']/div[3]/div/div/span/input | 123 + await driver + .findElement( + By.xpath("//div[@id='cardNumber-fieldset']/div[3]/div/div/span/input") + ) + .sendKeys('123'); + // 16 | type | xpath=//div[3]/div/div/div/div/div[2]/div/div/div/div/span/input | Francisco + await driver + .findElement( + By.xpath('//div[3]/div/div/div/div/div[2]/div/div/div/div/span/input') + ) + .sendKeys('Francisco'); + // 17 | click | xpath=//div[3]/div/div/span/input | + await driver.findElement(By.xpath('//div[3]/div/div/span/input')).click(); + // 18 | click | xpath=//div[@id='root']/div/div/div[2]/div/div[2]/form/div[2]/div[2]/button/div[3] | + await driver + .findElement( + By.xpath( + "//div[@id='root']/div/div/div[2]/div/div[2]/form/div[2]/div[2]/button/div[3]" + ) + ) + .click(); + // 19 | waitForElementPresent | xpath=//h1[contains(.,'Thank You!')] | 60000 + await driver.wait( + until.elementLocated(By.xpath("//h1[contains(.,'Thank You!')]")), + 60000 + ); + // 20 | assertText | //*[@id="__next"]/html/body/div/div[1]/div/div/h1 | Thank You! + assert( + (await driver + .findElement( + By.xpath('//*[@id="__next"]/html/body/div/div[1]/div/div/h1') + ) + .getText()) == 'Thank You!' + ); + }); +}); diff --git a/__tests__/E2E/makesanemptydonation.spec.js b/__tests__/E2E/makesanemptydonation.spec.js new file mode 100644 index 00000000..697730f5 --- /dev/null +++ b/__tests__/E2E/makesanemptydonation.spec.js @@ -0,0 +1,31 @@ +// Porto, 2022 +// This code was made with love by Francisco Bastos (https://www.linkedin.com/in/francisco-bastos-031369160/) +// for the curriculum unit of Comprehension and Evolution of Software at the +// master's in Software Engineering at the Faculty of Engineering of the University of Porto. +// Feel free to contact the author if any questions arise. +// +import { Builder, By } from 'selenium-webdriver'; + +describe('Makes an empty donation', function () { + jest.setTimeout(60000); + let driver; + // eslint-disable-next-line no-unused-vars + let vars; + beforeEach(async function () { + driver = await new Builder().forBrowser('chrome').build(); + vars = {}; + }); + afterEach(async function () { + await driver.quit(); + }); + it('Makes an empty donation', async function () { + // Test name: Makes an empty donation + // Step # | name | target | value + // 1 | open | / | + await driver.get('http://localhost:3000/'); + // 2 | setWindowSize | 1920x1080 | + await driver.manage().window().setRect({ width: 1920, height: 1080 }); + // 3 | click | xpath=//form/div/button | + await driver.findElement(By.xpath('//form/div/button')).click(); + }); +}); diff --git a/__tests__/E2E/makesanemptydonation2.spec.js b/__tests__/E2E/makesanemptydonation2.spec.js new file mode 100644 index 00000000..b642acd1 --- /dev/null +++ b/__tests__/E2E/makesanemptydonation2.spec.js @@ -0,0 +1,56 @@ +// Porto, 2022 +// This code was made with love by Francisco Bastos (https://www.linkedin.com/in/francisco-bastos-031369160/) +// for the curriculum unit of Comprehension and Evolution of Software at the +// master's in Software Engineering at the Faculty of Engineering of the University of Porto. +// Feel free to contact the author if any questions arise. +// +const { By } = require('selenium-webdriver'), + webdriver = require('selenium-webdriver'); + +describe('Makes an empty donation 2', function () { + let driver; + // eslint-disable-next-line no-unused-vars + let vars; + + beforeEach(async function () { + driver = new webdriver.Builder() + .withCapabilities(webdriver.Capabilities.chrome()) + .build(); + vars = {}; + }); + afterEach(async function () { + await driver.quit(); + }); + jest.setTimeout(60000); + it('Makes an empty donation 2', async function () { + // Test name: Makes an empty donation 2 + // Step # | name | target | value + // 1 | open | / | + await driver.get('http://localhost:3000/'); + // 2 | setWindowSize | 1920x1080 | + await driver.manage().window().setRect({ width: 1920, height: 1080 }); + // 3 | click | xpath=//div[@id='__next']/div/main/div/div[2]/div/div/div[3]/form/div/div[5]/select | + await driver + .findElement( + By.xpath( + "//div[@id='__next']/div/main/div/div[2]/div/div/div[3]/form/div/div[5]/select" + ) + ) + .click(); + // 4 | click | xpath=//select | + await driver.findElement(By.xpath('//select')).click(); + // 5 | select | xpath=//html/body/div[2]/div/main/div[1]/div[2]/div/div/div[3]/form/div/div[5]/select/option[2] | label=$5 + { + const dropdown = await driver.findElement( + By.xpath( + '/html/body/div[1]/div/main/div[1]/div[2]/div/div/div[3]/form/div/div[5]/select/option[2]' + ) + ); + await dropdown.findElement(By.xpath("//option[. = '$5']")).click(); + } + // 6 | click | xpath=//form/div/button | + await driver.findElement(By.css('.btn-accent:nth-child(7)')).click(); + // 7 | webdriverChooseOkOnVisibleConfirmation | xpath=//body/div[4]/div/div | + // await driver.switchTo().alert().accept(); + }); +}); diff --git a/__tests__/E2E/setup.js b/__tests__/E2E/setup.js new file mode 100644 index 00000000..cc1d4d39 --- /dev/null +++ b/__tests__/E2E/setup.js @@ -0,0 +1,23 @@ +// Porto, 2022 +// This code was made with love by Francisco Bastos (https://www.linkedin.com/in/francisco-bastos-031369160/) +// for the curriculum unit of Comprehension and Evolution of Software at the +// master's in Software Engineering at the Faculty of Engineering of the University of Porto. +// Feel free to contact the author if any questions arise. +// +var assert = require('assert'), + webdriver = require('selenium-webdriver'); +// This is just a simple test to see if selenium can communicate with chrome. +describe('Verify setup with Google Search', function () { + it('test case should work', function () { + var driver = new webdriver.Builder() + .withCapabilities(webdriver.Capabilities.chrome()) + .build(); + driver.get('http://www.google.com'); + var searchBox = driver.findElement(webdriver.By.name('q')); + searchBox.sendKeys('selenium node automation'); + searchBox.getAttribute('value').then(function (value) { + assert.equal(value, 'selenium node automation'); + }); + driver.quit(); + }); +}); diff --git a/components/CardsLayout.js b/components/CardsLayout.js index b6a65b57..da8b09d4 100644 --- a/components/CardsLayout.js +++ b/components/CardsLayout.js @@ -8,7 +8,7 @@ export default function CardsLayout({ children, description }) { const { hasItemsOnLeft, hasItemsOnRight, scrollRight, scrollLeft } = usePosition(ref); return ( -