plum-e2e 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,66 @@
1
1
  ![alt-text="social-preview"](https://repository-images.githubusercontent.com/936477779/e928fce3-6d4c-4609-92a0-0a1091c99752)
2
2
 
3
+ <p align="center">
4
+ 📖 <a href="https://github.com/silverlunah/plum/wiki">Wiki</a> |
5
+ 📦 <a href="https://www.npmjs.com/package/plum-e2e">npm</a>
6
+ </p>
7
+
8
+ ## Welcome to Plum!
9
+
10
+ Plum makes setting up your testing framework easy. In just a few seconds, you can run the scaffold tests and write your own tests!
11
+
12
+ By combining [Playwright](https://playwright.dev) and [Cucumber](https://cucumber.io), tests are easy to write and read. The code follows a POM (Page Object Model) structure, making it scalable and easy for developers to understand, while Cucumber test cases are written in [Gherkin](https://cucumber.io/docs/gherkin/) format, making them accessible to non-developers as well.
13
+
14
+ You can view, run, and schedule tests in a simple UI. You can even view the history of your runs in the reports page!
15
+
3
16
  **_Pre-requisite:_**
4
17
 
18
+ 1. Install Docker and ensure the Docker daemon is running.
19
+
20
+ ## For Users
21
+
22
+ People that want to use Plum as a test environment for their website.
23
+
5
24
  **_I. How to Run:_**
25
+
26
+ 1. `npm install -g plum-e2e`
27
+ 2. Create your project directory. Example: `mkdir my-test-folder`
28
+ 3. Go inside the folder you created `cd my-test-folder`
29
+ 4. Run `plum init`
30
+ 1. This will initialize Plum and will create your base files:
31
+ 1. `\tests` folder: This include sample test cases for [SauceLabs](https://www.saucedemo.com/v1/)
32
+ 2. `.env` file: Your starting .env file. You can set the BASE_URL to your own site after you're done with the scaffold tests.
33
+ 5. There are two ways to start testing:
34
+ 1. By running the server. Run:<br/> `plum start to start the server`
35
+ 2. Without running the server. Recommended while you're writing your tests. Run:<br/> `plum dev <@test-id>`. If no test ID is included, it will run all tests
36
+
37
+ ## Basic Structure
38
+
39
+ After you run `plum init`, these files will be created inside your project directory.
40
+
41
+ <pre>
42
+ ╠═ tests
43
+ ║ ╠═ features : Cucumber feature files, contains your test cases
44
+ ║ ╠═ step_definitions : Reference to steps in the feature files
45
+ ║ ╠═ pages : Contains functions used in step_definitions
46
+ ║ ╚═ utils : Utility files (Constants, utility codes, etc.)
47
+ ╚═ env. : Your .env file
48
+ </pre>
49
+
50
+ ## Tutorial
51
+
52
+ 1. For a complete guide on how to write tests, visit our [Coming Soon](https://github.com/silverlunah/plum/wiki)
53
+ 2. An easy way to learn is to check the scaffold files starting from the Feature files -> Step Definitions -> Page files and utils/world.ts for the CustomWorld initialization. Those are the main files you need to write a test case.
54
+
55
+ ## For Developers/Contributors
56
+
57
+ For people that want to contribute to the project
58
+
59
+ 1. Clone the project `git clone https://github.com/silverlunah/plum.git`
60
+ 2. `cd plum`
61
+ 3. Initialize the project by:<br/>`npm run init`
62
+ 4. Check if its running:<br/> `docker compose up --build -d`
63
+
64
+ ## Other
65
+
66
+ Plum is completely free to use! But if you want to share some love, here's my [PayPal](https://www.paypal.me/silverlunah) or [Wise](https://wise.com/pay/me/janneserjosee)
@@ -0,0 +1,24 @@
1
+ // loginPage.ts
2
+ import test, { Page } from '@playwright/test';
3
+ import { SAMPLE_CONSTANT } from '../utils/constants';
4
+ import { Utils } from '../utils/utils';
5
+
6
+ export class LoginPage {
7
+ private page: Page;
8
+ private utils: Utils;
9
+
10
+ constructor(page: Page) {
11
+ this.page = page;
12
+ this.utils = new Utils(this.page);
13
+ }
14
+
15
+ async goToLoginPage() {
16
+ console.log(SAMPLE_CONSTANT);
17
+ await this.utils.goToPage(process.env.BASE_URL as string);
18
+ await this.page.waitForTimeout(3000);
19
+ }
20
+
21
+ async skipTest() {
22
+ test.skip();
23
+ }
24
+ }
@@ -1,4 +1,4 @@
1
- const { Given, When, Then } = require('@cucumber/cucumber');
1
+ import { Given } from '@cucumber/cucumber';
2
2
 
3
3
  Given('I am in Demo Sauce Login page', async function () {
4
4
  await this.loginPage.goToLoginPage();
@@ -0,0 +1 @@
1
+ export const SAMPLE_CONSTANT = 'this is a constant';
@@ -0,0 +1,36 @@
1
+ import { Before, After, setWorldConstructor, ITestCaseHookParameter } from '@cucumber/cucumber';
2
+ import { chromium } from 'playwright';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { CustomWorld } from './world';
6
+ import dotenv from 'dotenv';
7
+
8
+ dotenv.config();
9
+ setWorldConstructor(CustomWorld);
10
+
11
+ Before(async function (this: CustomWorld) {
12
+ const isHeadless = process.env.IS_HEADLESS?.toLowerCase() !== 'false';
13
+
14
+ this.browser = await chromium.launch({ headless: isHeadless });
15
+ this.context = await this.browser.newContext();
16
+ this.page = await this.context.newPage();
17
+
18
+ this.initPages(this.page);
19
+ });
20
+
21
+ After(async function (this: CustomWorld, scenario: ITestCaseHookParameter) {
22
+ if (scenario.result?.status === 'FAILED' && this.page) {
23
+ const screenshotDir = path.join('reports', 'screenshots');
24
+ if (!fs.existsSync(screenshotDir)) {
25
+ fs.mkdirSync(screenshotDir, { recursive: true });
26
+ }
27
+
28
+ const screenshotPath = path.join(screenshotDir, `screenshot_${Date.now()}.png`);
29
+ await this.page.screenshot({ path: screenshotPath });
30
+
31
+ const screenshotData = fs.readFileSync(screenshotPath);
32
+ await this.attach(screenshotData, 'image/png');
33
+ }
34
+
35
+ await this.browser?.close();
36
+ });
@@ -0,0 +1,13 @@
1
+ import { Page } from '@playwright/test';
2
+
3
+ export class Utils {
4
+ private page: Page;
5
+
6
+ constructor(page: Page) {
7
+ this.page = page;
8
+ }
9
+
10
+ async goToPage(url: string) {
11
+ await this.page.goto(url);
12
+ }
13
+ }
@@ -0,0 +1,25 @@
1
+ import { IWorldOptions, setWorldConstructor, World } from '@cucumber/cucumber';
2
+ import { Browser, Page, BrowserContext } from 'playwright';
3
+ import { LoginPage } from '../pages/LoginPage';
4
+ import { Utils } from './utils';
5
+
6
+ export class CustomWorld extends World {
7
+ browser!: Browser;
8
+ context!: BrowserContext;
9
+ page!: Page;
10
+
11
+ loginPage!: LoginPage;
12
+ utils!: Utils;
13
+
14
+ constructor(options: IWorldOptions) {
15
+ super(options);
16
+ }
17
+
18
+ initPages(page: Page) {
19
+ this.utils = new Utils(page);
20
+ this.loginPage = new LoginPage(page);
21
+ // Add other pages here
22
+ }
23
+ }
24
+
25
+ setWorldConstructor(CustomWorld);
@@ -16,19 +16,32 @@
16
16
  */
17
17
 
18
18
  const { execSync } = require('child_process');
19
- const tag = process.env.TAG; // Read the TAG environment variable
19
+ const tag = process.env.TAG;
20
20
 
21
21
  try {
22
- // Run the tests with the tag filter, only if a tag is provided
23
- const cucumberCommand = tag
24
- ? `cucumber-js tests/features/**/*.feature --format json:reports/cucumber_report.json --tags "${tag}"`
25
- : `cucumber-js tests/features/**/*.feature --format json:reports/cucumber_report.json`;
22
+ const baseCommand = [
23
+ 'npx',
24
+ 'cross-env',
25
+ 'TS_NODE_TRANSPILE_ONLY=true',
26
+ 'cucumber-js',
27
+ 'tests/features/**/*.feature',
28
+ '--require-module',
29
+ 'ts-node/register',
30
+ '--require',
31
+ 'tests/step_definitions/**/*.ts',
32
+ '--format',
33
+ 'json:reports/cucumber_report.json'
34
+ ];
26
35
 
36
+ if (tag) {
37
+ baseCommand.push('--tags', `"${tag}"`);
38
+ }
39
+
40
+ const cucumberCommand = baseCommand.join(' ');
27
41
  execSync(cucumberCommand, { stdio: 'inherit' });
28
42
  } catch (error) {
29
43
  console.error('Tests failed:', error.message);
30
44
  } finally {
31
- // Always run the report generation after tests (even if they fail)
32
45
  try {
33
46
  execSync('node config/scripts/generate-report.js', { stdio: 'inherit' });
34
47
  } catch (error) {
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "default": {
3
- "require": ["tests/step_definitions/*.js", "tests/utils/hooks.js"],
4
- "featurePaths": ["tests/features/**/*.feature"]
3
+ "require": ["tests/step_definitions/*.ts", "tests/utils/hooks.ts"],
4
+ "featurePaths": ["tests/features/**/*.feature"],
5
+ "requireModule": ["ts-node/register"]
5
6
  }
6
7
  }