-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CPS-562: E2E test Basic Structure #1
Conversation
63ff0b9
to
52738f8
Compare
a742049
to
02da8ca
Compare
f71fc41
to
711b2e4
Compare
897fea6
to
7950a8e
Compare
708a722
to
0d05713
Compare
0d05713
to
cda7776
Compare
9d00133
to
30ab776
Compare
c4554f4
to
3bab997
Compare
3bab997
to
dd3f74a
Compare
src/pages/base/manage-entity.page.ts
Outdated
* @returns {Promise<any>} promise | ||
*/ | ||
async waitForPageLoad (page: Page): Promise<any> { | ||
return await page.waitForSelector('.civicase__case-filter-panel__button'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@deb1990 Please move all the selectors within page classes to variables and then reuse the variables inside the tests. To make it a bit more accessible we can create array and pop all the elements inside the array so we can refer to elements by "PageName.selectors.ElementName"
eg:
static selectors = {
usernameTextBox: 'input[data-test="username"]',
passwordTextBox: 'input[data-test="password"]',
loginButton: 'input[data-test="login-button"]'
};
This would be useful when tests are using elements from more than one page in E2E scenarios.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@deb1990 @tunbola @lisandro-compucorp have we considered the use of Cucumber for writing the spec files?
I have the Gherkin syntax much more readable and explanatory. I think writing new tests can be easier as well.
Instead of having an intimidating file such as
tests/prospects/manage-prospects/prospect-page-title.spec.ts
We can have something like
Feature: Prospect Dashboard
Scenario: Prospect Dashboard Title
When I log in as a "Prospect User"
And I navigate to the "Prospect Dashboard"
Then the page title should be "Manage Prospectings"
Scenario: Restricted Access
When I log in as a "CiviCRM User"
And I navigate to the "Prospect Dashboard"
Then I should get an access denied message
The cool thing about these examples is that we can reuse sentences in other spec files.
The "Given I log in as a *" can be defined in code as follows:
Given("I log in as a {string}", function (userRole) {
await browser.loginUsingCookiesAs(userRole);
});
Once we define things like "login as" or "navigate to", we don't need to define these in the code again, and again. We just need to mention the steps in the spec files.
The Gherkin files also remove a lot of code that is necessary to run tests but not to understand what
we want to test such as
beforeAll(async () => {
await browser.setup();
});
afterAll(async () => {
await browser.close();
});
beforeEach(async () => {
page = await browser.newPage();
manageProspects = new ManageProspects(browser);
});
afterEach(async () => {
await browser.takeScreenshotWhenFailedAndClose(page);
});
And even code that is perfectly readable for programmers can be more easily understood in a test context:
await manageProspects.navigate(page);
await manageProspects.waitForPageLoad(page);
vs
And I navigate to "Prospect Dashboard"
Let me know what you guys think and we can discuss in detail.
gulp-tasks/jest.ts
Outdated
export default jestTask; | ||
|
||
/** | ||
* @returns {Promise<void>} promise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why document the type when TypeScript is already doing that?
I don't see much value in adding these unless there's a specific note to add.
/** | ||
* @returns {Promise<void>} promise | ||
*/ | ||
async function jestTask (): Promise<void> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also think the return value is inferred by TypeScript because there is no return
and because of async
. TypeScript would usually infer the return value and there is no need to define it in most cases. Unless we want to make it a rule to always define it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah Standard JS is enforcing this, which is fine because now we are documenting the return type anymore using JSDoc.
option_group_id?: string | ||
name?: string | ||
definition?: any | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can define every possible parameter here, but different API endpoints have different parameters. This list might grow exponentially over time.
The actual type for API parameters would be
{
[key: string]: any,
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, in that case, should we not use any type? Because [key: string]: any,
defeats the purpose, or what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[key: string]: any
is a bit more specific than any
because I don't think you can pass numbers to that parameter.
*/ | ||
constructor (public browser: BrowserService) { | ||
super(browser); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to define the constructor method if we are not going to have a different behaviour from the base class.
/** | ||
* @returns {string} page title | ||
*/ | ||
abstract getPageTitle (): string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to redefine this one either.
/** | ||
* @returns {string} page title | ||
*/ | ||
getPageUrl (): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to define the return type. TypeScript knows that you are returning a string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is enforced by StandardJS.
src/pages/cases/manage-case.page.ts
Outdated
constructor (public browser: BrowserService) { | ||
super(browser); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove
constructor (public browser: BrowserService) { | ||
super(browser); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove
* @param {CiviApiQuery} params parameters | ||
* @returns {object[]} created entities | ||
*/ | ||
create (params: CiviApiParam[]): object[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From experience, I try not to add the return type at all. TypeScript is smart enough to determine the return type. And if it doesn't figure it out, it means one of your function call return types is not properly defined. It's easier to debug proper TypeScript when you don't add the return type hint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is enforced by StandardJS.
import BrowserService from '../../../src/services/utils/browser.service'; | ||
import { ManageApplications } from '../../../src/pages/awards/manage-applications.page'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can import things from the root if configured:
https://stackoverflow.com/questions/42123382/import-module-from-root-path-in-typescript
import BrowserService from '../../../src/services/utils/browser.service';
// vs
import BrowserService from 'services/utils/browser.service';
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even better when you don't have to count the number of folders to go back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolute paths are currently not supported in ts-node
. wclr/ts-node-dev#95
I tried some of the solutions mentioned, but its not working and I have already spent a lot of time in this. Lets leave this for now, I will keep trying.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't worry about this, but if you want to check this in the future it seems this can work:
https://dev.to/larswaechter/path-aliases-with-typescript-in-nodejs-4353
I have also created a package.json file in the src
folder and then reference it in the root package.json
. Like this:
// /package.json
{
"dependencies": {
"cases-e2e": "./src"
}
}
// /src/pacakge.json
{
"name": "cases-e2e"
}
Then on any TS file I can do this:
import something from 'cases-e2e/a/path/from/src/something';
.github/workflows/endtoend.yml
Outdated
|
||
- name: Install E2E Test Suite | ||
run: | | ||
git clone https://github.com/compucorp/cases-product-suite-e2e-tests.git --branch CPS-562-e2e-basic-setup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should switch the branch to be cloned here to master
Overview
This PR Creates a basic structure for E2E tests using Playwright, Jest and Gulp.
Technical Details
Refer https://github.com/compucorp/cases-product-suite-e2e-tests/blob/CPS-562-e2e-basic-setup/readme.md.