Skip to content
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

adding end-to-end tests for fasten-sources (sandboxes) #475

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/ci-sources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Fasten-Sources End-to-End Tests
# Todo: this should run on a schedule as well (weekly?)
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
env:
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 21
- run: cd frontend && yarn install
- name: Run Browserstack tests
run: cd frontend && yarn run e2e
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: frontend/playwright-report/
retention-days: 30
6 changes: 6 additions & 0 deletions backend/pkg/models/source_credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,12 @@ func (s *SourceCredential) RefreshDynamicClientAccessToken() error {
return fmt.Errorf("an error occurred while sending dynamic client token request, %s", err)
}

//dump, err := httputil.DumpResponse(tokenResp, true)
//if err != nil {
// return fmt.Errorf("an error occurred while introspecting response")
//}
//fmt.Printf("%q", dump)
//
defer tokenResp.Body.Close()
if tokenResp.StatusCode >= 300 || tokenResp.StatusCode < 200 {

Expand Down
52 changes: 52 additions & 0 deletions frontend/e2e/browserstack.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const base = require('@playwright/test');
const cp = require('child_process');
const clientPlaywrightVersion = cp
.execSync('npx playwright --version')
.toString()
.trim()
.split(' ')[1];
const BrowserStackLocal = require('browserstack-local');
const util = require('util');

// BrowserStack Specific Capabilities.
// Set 'browserstack.local:true For Local testing
const caps = {
browser: 'chrome',
os: 'osx',
os_version: 'catalina',
name: 'My first playwright test',
build: 'playwright-build',
'browserstack.username': process.env.BROWSERSTACK_USERNAME || 'USERNAME',
'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY || 'ACCESSKEY',
'browserstack.local': process.env.BROWSERSTACK_LOCAL || true,
'client.playwrightVersion': clientPlaywrightVersion,
};

exports.bsLocal = new BrowserStackLocal.Local();

// replace YOUR_ACCESS_KEY with your key. You can also set an environment variable - "BROWSERSTACK_ACCESS_KEY".
exports.BS_LOCAL_ARGS = {
key: process.env.BROWSERSTACK_ACCESS_KEY || 'ACCESSKEY',
};

// Patching the capabilities dynamically according to the project name.
const patchCaps = (name, title) => {
let combination = name.split(/@browserstack/)[0];
let [browerCaps, osCaps] = combination.split(/:/);
let [browser, browser_version] = browerCaps.split(/@/);
let osCapsSplit = osCaps.split(/ /);
let os = osCapsSplit.shift();
let os_version = osCapsSplit.join(' ');
caps.browser = browser ? browser : 'chrome';
caps.os_version = browser_version ? browser_version : 'latest';
caps.os = os ? os : 'osx';
caps.os_version = os_version ? os_version : 'catalina';
caps.name = title;
};

exports.getCdpEndpoint = (name, title) => {
patchCaps(name, title)
const cdpUrl = `wss:https://cdp.browserstack.com/playwright?caps=${encodeURIComponent(JSON.stringify(caps))}`
console.log(`--> ${cdpUrl}`)
return cdpUrl;
}
24 changes: 24 additions & 0 deletions frontend/e2e/global-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// global-setup.js
const { bsLocal, BS_LOCAL_ARGS } = require('./browserstack.config');
const { promisify } = require('util');
const sleep = promisify(setTimeout);
const redColour = '\x1b[31m';
const whiteColour = '\x1b[0m';
module.exports = async () => {
console.log('Starting BrowserStackLocal ...');
// Starts the Local instance with the required arguments
let localResponseReceived = false;
bsLocal.start(BS_LOCAL_ARGS, (err) => {
if (err) {
console.error(
`${redColour}Error starting BrowserStackLocal${whiteColour}`
);
} else {
console.log('BrowserStackLocal Started');
}
localResponseReceived = true;
});
while (!localResponseReceived) {
await sleep(1000);
}
};
18 changes: 18 additions & 0 deletions frontend/e2e/global-teardown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// global-teardown.js
const { bsLocal } = require('./browserstack.config');
const { promisify } = require('util');
const sleep = promisify(setTimeout);
module.exports = async () => {
// Stop the Local instance after your test run is completed, i.e after driver.quit
let localStopped = false;

if (bsLocal && bsLocal.isRunning()) {
bsLocal.stop(() => {
localStopped = true;
console.log('Stopped BrowserStackLocal');
});
while (!localStopped) {
await sleep(1000);
}
}
}
22 changes: 22 additions & 0 deletions frontend/e2e/src/local_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @ts-check
const { test, expect } = require('@playwright/test');

test('Local Testing', async ({ page },testInfo) => {

try{

await page.evaluate(_ => {},`browserstack_executor: ${JSON.stringify({action: "setSessionName", arguments: {name:testInfo.project.name}})}`);

await page.waitForTimeout(5000);

await page.goto('https://www.example.com/');

await page.evaluate(_ => {}, `browserstack_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {status: 'passed',reason: 'Local success'}})}`);

} catch (e) {
console.log(e);
await page.evaluate(_ => {}, `browserstack_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {status: 'failed',reason: 'Local fail'}})}`);

}

});
40 changes: 40 additions & 0 deletions frontend/e2e/src/sample_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// @ts-check
const { test, expect } = require('@playwright/test');

test('BstackDemo Add to cart', async ({ page },testInfo) => {

try{

await page.evaluate(_ => {},`browserstack_executor: ${JSON.stringify({action: "setSessionName", arguments: {name:testInfo.project.name}})}`);
await page.waitForTimeout(5000);

await page.goto('https://www.bstackdemo.com/',{ waitUntil: 'networkidle' });
await page.locator('[id="\\32 "]').getByText('Add to cart').click();
await page.getByText('Checkout').click();
await page.locator('#username svg').click();
await page.locator('#react-select-2-option-0-0').click();
await page.locator('#password svg').click();
await page.locator('#react-select-3-option-0-0').click();
await page.getByRole('button', { name: 'Log In' }).click();
await page.getByLabel('First Name').click();
await page.getByLabel('First Name').fill('SampleFirst');
await page.getByLabel('Last Name').click();
await page.getByLabel('Last Name').fill('sampleLast');
await page.getByLabel('Address').click();
await page.getByLabel('Address').fill('sampleAddress');
await page.getByLabel('State/Province').click();
await page.getByLabel('State/Province').fill('SampleState');
await page.getByLabel('Postal Code').click();
await page.getByLabel('Postal Code').fill('123456');
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByRole('button', { name: 'Continue Shopping »' }).click();

await page.evaluate(_ => {}, `browserstack_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {status: 'passed',reason: 'Product added to cart'}})}`);

} catch (e) {
console.log(e);
await page.evaluate(_ => {}, `browserstack_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {status: 'failed',reason: 'Test failed'}})}`);

}

});
4 changes: 3 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"build": "ng build --output-path=../dist",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"e2e": "npx playwright test",
"dist": "ng build --watch --output-path=../dist",
"storybook": "ng run fastenhealth:storybook",
"build-storybook": "ng run fastenhealth:build-storybook"
Expand Down Expand Up @@ -67,6 +67,7 @@
"@angular/compiler-cli": "^14.1.3",
"@angular/language-service": "^14.1.3",
"@compodoc/compodoc": "^1.1.19",
"@playwright/test": "^1.44.1",
"@storybook/addon-essentials": "^7.0.7",
"@storybook/addon-interactions": "^7.0.7",
"@storybook/addon-links": "^7.0.7",
Expand All @@ -75,6 +76,7 @@
"@storybook/testing-library": "^0.0.14-next.2",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"browserstack-local": "^1.5.5",
"chromatic": "^6.19.8",
"codelyzer": "^5.1.2",
"fishery": "^2.2.2",
Expand Down
85 changes: 85 additions & 0 deletions frontend/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// @ts-check
const { devices } = require('@playwright/test');
const { getCdpEndpoint } = require('./e2e/browserstack.config.ts')

/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();


/**
* @see https://playwright.dev/docs/test-configuration
* @type {import('@playwright/test').PlaywrightTestConfig}
*/
const config = {
testDir: './e2e/src',
testMatch: '**/*.ts',

globalSetup: require.resolve('./e2e/global-setup.ts'),
globalTeardown: require.resolve('./e2e/global-teardown.ts'),

/* Maximum time one test can run for. */
timeout: 90 * 1000,
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
* For example in `await expect(locator).toHaveText();`
*/
timeout: 5000
},
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
actionTimeout: 0,
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'https://localhost:3000',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},

/* Configure projects for major browsers */
projects: [
{
name: 'chrome@latest:Windows 11',
use: {
connectOptions: { wsEndpoint: getCdpEndpoint('chrome@latest:Windows 11','test1') },
},
}
// {
// name: 'playwright-webkit@latest:OSX Ventura',
// use: {
// connectOptions: { wsEndpoint: getCdpEndpoint('playwright-webkit@latest:OSX Ventura', 'test2') }
// },
// },
// {
// name: 'playwright-firefox:Windows 11',
// use: {
// connectOptions: { wsEndpoint: getCdpEndpoint('playwright-firefox:Windows 11', 'test3') }
// },
// }
],

/* Folder for test artifacts such as screenshots, videos, traces, etc. */
// outputDir: 'test-results/',

/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// port: 3000,
// },
};

module.exports = config;
Loading
Loading