chore: adding selenium tests with browserstack (#2570)
Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
This commit is contained in:
parent
8227258b4a
commit
e8d65f22d2
|
@ -22,8 +22,9 @@ jobs:
|
|||
run: npm install semver
|
||||
|
||||
- name: Check API dependency semantics (stable)
|
||||
run: lerna exec --ignore propagation-validation-server "node ../../scripts/peer-api-check.js"
|
||||
working-directory: packages
|
||||
run: lerna exec --ignore propagation-validation-server --ignore propagation-validation-server --ignore @opentelemetry/selenium-tests "node ../../scripts/peer-api-check.js"
|
||||
|
||||
- name: Check API dependency semantics (experimental)
|
||||
working-directory: experimental
|
||||
run: lerna exec --ignore propagation-validation-server "node ../../../scripts/peer-api-check.js"
|
||||
run: lerna exec --ignore propagation-validation-server --ignore @opentelemetry/selenium-tests "node ../../../scripts/peer-api-check.js"
|
||||
|
|
|
@ -35,7 +35,7 @@ jobs:
|
|||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
npm install --ignore-scripts
|
||||
npx lerna bootstrap --no-ci --hoist --nohoist='zone.js'
|
||||
npx lerna bootstrap --no-ci --hoist --nohoist='zone.js' --ignore @opentelemetry/selenium-tests
|
||||
|
||||
- name: Build 🔧
|
||||
run: |
|
||||
|
@ -111,7 +111,7 @@ jobs:
|
|||
working-directory: experimental
|
||||
run: |
|
||||
npm install --ignore-scripts
|
||||
npx lerna bootstrap --no-ci --hoist --nohoist='zone.js'
|
||||
npx lerna bootstrap --no-ci --hoist --nohoist='zone.js' --ignore @opentelemetry/selenium-tests
|
||||
|
||||
- name: Build 🔧
|
||||
working-directory: experimental
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"packages": [
|
||||
"benchmark/*",
|
||||
"packages/*",
|
||||
"integration-tests/*"
|
||||
"integration-tests/*",
|
||||
"selenium-tests"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
tests_output
|
||||
tmp
|
|
@ -0,0 +1,54 @@
|
|||
## Selenium Tests
|
||||
|
||||
Selenium tests are to help verify the working of opentelemetry in different browsers. For that the nightwatch is used.
|
||||
This can be run either locally or in github actions with usage of browserstack.
|
||||
Browser stack also gives possibility of running tests in browserstack on different browsers using our local environment.
|
||||
This helps to test and debug things locally using any browser we want.
|
||||
|
||||
## Running tests locally using local browser - this is also useful when adding new test
|
||||
|
||||
1. run server
|
||||
|
||||
```shell
|
||||
npm run server
|
||||
```
|
||||
|
||||
1. run local test for example for xhr
|
||||
|
||||
```shell
|
||||
npm run local:xhr
|
||||
```
|
||||
|
||||
Please wait a bit it should run selenium tests using our local version of chrome
|
||||
|
||||
## Running tests locally using browser stack account - for that you need to have a browser stack account
|
||||
|
||||
If you have it please create a file ".env" based on "example.env"
|
||||
|
||||
1. run server
|
||||
|
||||
```shell
|
||||
npm run server
|
||||
```
|
||||
|
||||
1. Run local test for example for xhr
|
||||
|
||||
```shell
|
||||
npm run local:bs:xhr
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
1. Folder pages contains all the pages that can be entered after running `npn run server` at <http://localhost:8090/> .
|
||||
These are fully functioning pages and can be run without running tests.
|
||||
|
||||
2. To be able to test it automatically instead of manually we have to create a test. Tests are kept in folder "tests".
|
||||
For each page there is a corresponding folder with exactly the same name. There are additional 2 files
|
||||
|
||||
- helper.js - this file keeps some helpers functions that are included in page automatically and they are available in tests only in section "execute".
|
||||
This is because this section is being sent to the browser and executed automatically. This is the only way of "sending" and "reading" data back to test
|
||||
When data is being sent between browser and selenium it needs to be stringified that's why we have one more helper for that called "JSONSafeStringify"
|
||||
The last helper is the one that helps to verify test has finished successfully "OTELSeleniumDone".
|
||||
|
||||
- tracing.js - this file contains the skeleton for tracing and export function "loadOtel" this is a helper function that accepts instrumentations as param.
|
||||
This way it is easy to add different tests that has different lists of instrumentations.
|
|
@ -0,0 +1,33 @@
|
|||
module.exports = function (api) {
|
||||
api.cache(true);
|
||||
const presets = [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
corejs: {
|
||||
version: '3',
|
||||
proposals: true,
|
||||
},
|
||||
useBuiltIns: 'entry',
|
||||
targets: {
|
||||
// 'edge': 16,
|
||||
// 'safari': 9,
|
||||
// 'firefox': 57,
|
||||
'ie': 11,
|
||||
// 'ios': 9,
|
||||
// 'chrome': 49,
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
const plugins = [
|
||||
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }],
|
||||
['@babel/plugin-proposal-class-properties', { 'loose': true }],
|
||||
["@babel/plugin-proposal-private-methods", { "loose": true }],
|
||||
["@babel/plugin-proposal-private-property-in-object", { "loose": true }],
|
||||
];
|
||||
return {
|
||||
presets,
|
||||
plugins,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
BROWSERSTACK_USER="YOUR USER"
|
||||
BROWSERSTACK_KEY="YOUR BROWSER STACK KEY"
|
|
@ -0,0 +1,287 @@
|
|||
// Autogenerated by Nightwatch
|
||||
// Refer to the online docs for more details: https://nightwatchjs.org/gettingstarted/configuration/
|
||||
const Services = {}; loadServices();
|
||||
|
||||
module.exports = {
|
||||
// An array of folders (excluding subfolders) where your tests are located;
|
||||
// if this is not specified, the test source must be passed as the second argument to the test runner.
|
||||
src_folders: [],
|
||||
|
||||
// See https://nightwatchjs.org/guide/working-with-page-objects/
|
||||
page_objects_path: '',
|
||||
|
||||
// See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands
|
||||
custom_commands_path: '',
|
||||
|
||||
// See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-assertions
|
||||
custom_assertions_path: '',
|
||||
|
||||
// See https://nightwatchjs.org/guide/#external-globals
|
||||
globals_path : '',
|
||||
|
||||
webdriver: {},
|
||||
|
||||
test_settings: {
|
||||
default: {
|
||||
disable_error_log: false,
|
||||
launch_url: 'https://nightwatchjs.org',
|
||||
|
||||
screenshots: {
|
||||
enabled: false,
|
||||
path: 'screens',
|
||||
on_failure: true
|
||||
},
|
||||
|
||||
desiredCapabilities: {
|
||||
browserName : 'firefox'
|
||||
},
|
||||
|
||||
webdriver: {
|
||||
start_process: true,
|
||||
server_path: (Services.geckodriver ? Services.geckodriver.path : '')
|
||||
}
|
||||
},
|
||||
|
||||
safari: {
|
||||
desiredCapabilities : {
|
||||
browserName : 'safari',
|
||||
alwaysMatch: {
|
||||
acceptInsecureCerts: false
|
||||
}
|
||||
},
|
||||
webdriver: {
|
||||
port: 4445,
|
||||
start_process: true,
|
||||
server_path: '/usr/bin/safaridriver'
|
||||
}
|
||||
},
|
||||
|
||||
firefox: {
|
||||
desiredCapabilities : {
|
||||
browserName : 'firefox',
|
||||
alwaysMatch: {
|
||||
acceptInsecureCerts: true,
|
||||
'moz:firefoxOptions': {
|
||||
args: [
|
||||
// '-headless',
|
||||
// '-verbose'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
webdriver: {
|
||||
start_process: true,
|
||||
port: 4444,
|
||||
server_path: (Services.geckodriver ? Services.geckodriver.path : ''),
|
||||
cli_args: [
|
||||
// very verbose geckodriver logs
|
||||
// '-vv'
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
chrome: {
|
||||
desiredCapabilities : {
|
||||
browserName : 'chrome',
|
||||
'goog:chromeOptions' : {
|
||||
// More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/
|
||||
//
|
||||
// This tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78)
|
||||
w3c: false,
|
||||
args: [
|
||||
//'--no-sandbox',
|
||||
//'--ignore-certificate-errors',
|
||||
//'--allow-insecure-localhost',
|
||||
//'--headless'
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
webdriver: {
|
||||
start_process: true,
|
||||
port: 9515,
|
||||
server_path: (Services.chromedriver ? Services.chromedriver.path : ''),
|
||||
cli_args: [
|
||||
// --verbose
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
edge: {
|
||||
desiredCapabilities : {
|
||||
browserName : 'MicrosoftEdge',
|
||||
'ms:edgeOptions' : {
|
||||
w3c: false,
|
||||
// More info on EdgeDriver: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options
|
||||
args: [
|
||||
//'--headless'
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
webdriver: {
|
||||
start_process: true,
|
||||
// Download msedgedriver from https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/
|
||||
// and set the location below:
|
||||
server_path: '',
|
||||
cli_args: [
|
||||
// --verbose
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Configuration for when using the browserstack.com cloud service |
|
||||
// |
|
||||
// Please set the username and access key by setting the environment variables: |
|
||||
// - BROWSERSTACK_USER |
|
||||
// - BROWSERSTACK_KEY |
|
||||
// .env files are supported |
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
browserstack: {
|
||||
selenium: {
|
||||
host: 'hub-cloud.browserstack.com',
|
||||
port: 443
|
||||
},
|
||||
// More info on configuring capabilities can be found on:
|
||||
// https://www.browserstack.com/automate/capabilities?tag=selenium-4
|
||||
desiredCapabilities: {
|
||||
'bstack:options' : {
|
||||
userName: '${BROWSERSTACK_USER}',
|
||||
accessKey: '${BROWSERSTACK_KEY}',
|
||||
}
|
||||
},
|
||||
|
||||
disable_error_log: true,
|
||||
webdriver: {
|
||||
timeout_options: {
|
||||
timeout: 15000,
|
||||
retry_attempts: 3
|
||||
},
|
||||
keep_alive: true,
|
||||
start_process: false
|
||||
}
|
||||
},
|
||||
|
||||
'browserstack.local': {
|
||||
extends: 'browserstack',
|
||||
desiredCapabilities: {
|
||||
'browserstack.local': true,
|
||||
'browserstack.console': 'errors'
|
||||
}
|
||||
},
|
||||
|
||||
'browserstack.chrome': {
|
||||
extends: 'browserstack',
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome',
|
||||
chromeOptions : {
|
||||
w3c: false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'browserstack.firefox': {
|
||||
extends: 'browserstack',
|
||||
desiredCapabilities: {
|
||||
browserName: 'firefox'
|
||||
}
|
||||
},
|
||||
|
||||
'browserstack.ie': {
|
||||
extends: 'browserstack',
|
||||
desiredCapabilities: {
|
||||
browserName: 'internet explorer',
|
||||
browserVersion: '11.0'
|
||||
}
|
||||
},
|
||||
|
||||
'browserstack.safari': {
|
||||
extends: 'browserstack',
|
||||
desiredCapabilities: {
|
||||
browserName: 'safari'
|
||||
}
|
||||
},
|
||||
|
||||
'browserstack.local_chrome': {
|
||||
extends: 'browserstack.local',
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome'
|
||||
}
|
||||
},
|
||||
|
||||
'browserstack.local_firefox': {
|
||||
extends: 'browserstack.local',
|
||||
desiredCapabilities: {
|
||||
browserName: 'firefox'
|
||||
}
|
||||
},
|
||||
'browserstack.local_ie': {
|
||||
extends: 'browserstack.local',
|
||||
desiredCapabilities: {
|
||||
browserName: 'internet explorer',
|
||||
browserVersion: '11.0'
|
||||
}
|
||||
},
|
||||
'browserstack.local_safari': {
|
||||
extends: 'browserstack.local',
|
||||
desiredCapabilities: {
|
||||
browserName: 'safari',
|
||||
}
|
||||
},
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Configuration for when using the Selenium service, either locally or remote, |
|
||||
// like Selenium Grid |
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
selenium_server: {
|
||||
// Selenium Server is running locally and is managed by Nightwatch
|
||||
selenium: {
|
||||
start_process: true,
|
||||
port: 4444,
|
||||
server_path: (Services.seleniumServer ? Services.seleniumServer.path : ''),
|
||||
cli_args: {
|
||||
'webdriver.gecko.driver': (Services.geckodriver ? Services.geckodriver.path : ''),
|
||||
'webdriver.chrome.driver': (Services.chromedriver ? Services.chromedriver.path : '')
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'selenium.chrome': {
|
||||
extends: 'selenium_server',
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome',
|
||||
chromeOptions : {
|
||||
w3c: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'selenium.firefox': {
|
||||
extends: 'selenium_server',
|
||||
desiredCapabilities: {
|
||||
browserName: 'firefox',
|
||||
'moz:firefoxOptions': {
|
||||
args: [
|
||||
// '-headless',
|
||||
// '-verbose'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function loadServices() {
|
||||
try {
|
||||
Services.seleniumServer = require('selenium-server');
|
||||
} catch (err) {}
|
||||
|
||||
try {
|
||||
Services.chromedriver = require('chromedriver');
|
||||
} catch (err) {}
|
||||
|
||||
try {
|
||||
Services.geckodriver = require('geckodriver');
|
||||
} catch (err) {}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"name": "@opentelemetry/selenium-tests",
|
||||
"version": "0.0.1",
|
||||
"description": "OpenTelemetry Selenium Tests",
|
||||
"main": "index.js",
|
||||
"repository": "open-telemetry/opentelemetry-js",
|
||||
"scripts": {
|
||||
"all:bs": "nightwatch ./tests --parallel --env browserstack.chrome,browserstack.safari,browserstack.firefox",
|
||||
"all:local": "nightwatch ./tests --parallel --env selenium.chrome",
|
||||
"local:bs:fetch": "node scripts/local.runner.js --test ./tests/fetch/fetch.js --parallel --env browserstack.local_chrome,browserstack.local_firefox,browserstack.local_safari",
|
||||
"local:bs:xhr": "node scripts/local.runner.js --test ./tests/xhr/xhr.js --parallel --env browserstack.local_chrome,browserstack.local_firefox,browserstack.local_ie,browserstack.local_safari",
|
||||
"local:fetch": "nightwatch ./tests/fetch/fetch.js --env selenium.chrome",
|
||||
"local:xhr": "nightwatch ./tests/xhr/xhr.js --env selenium.chrome",
|
||||
"server": "webpack serve --progress --port 8090 --config webpack.dev.js --hot --host 0.0.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"opentelemetry",
|
||||
"web",
|
||||
"tracing",
|
||||
"profiling",
|
||||
"metrics",
|
||||
"stats"
|
||||
],
|
||||
"author": "OpenTelemetry Authors",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "private"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.8",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@babel/plugin-proposal-decorators": "^7.15.8",
|
||||
"@babel/plugin-transform-runtime": "^7.15.8",
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@opentelemetry/api": "^1.0.3",
|
||||
"babel-loader": "^8.2.3",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"browserstack-local": "^1.4.8",
|
||||
"chromedriver": "^95.0.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"fast-safe-stringify": "^2.1.1",
|
||||
"geckodriver": "^2.0.4",
|
||||
"nightwatch": "^1.7.11",
|
||||
"selenium-server": "^3.141.59",
|
||||
"terser-webpack-plugin": "^5.2.4",
|
||||
"webpack": "^5.60.0",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"webpack-dev-server": "^4.3.1",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@opentelemetry/context-zone-peer-dep": "^1.0.0",
|
||||
"@opentelemetry/core": "^1.0.0",
|
||||
"@opentelemetry/exporter-otlp-http": "^0.26.0",
|
||||
"@opentelemetry/exporter-zipkin": "^1.0.0",
|
||||
"@opentelemetry/instrumentation": "^0.26.0",
|
||||
"@opentelemetry/instrumentation-fetch": "^0.26.0",
|
||||
"@opentelemetry/instrumentation-xml-http-request": "^0.26.0",
|
||||
"@opentelemetry/sdk-metrics-base": "^0.26.0",
|
||||
"@opentelemetry/sdk-trace-base": "^1.0.0",
|
||||
"@opentelemetry/sdk-trace-web": "^1.0.0",
|
||||
"zone.js": "^0.10.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Fetch Plugin</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Example of using Web Tracer with Fetch plugin and console exporter
|
||||
<script type="text/javascript" src="fetch.js"></script>
|
||||
<br/>
|
||||
<button id="button1">Test</button>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,51 @@
|
|||
'use strict';
|
||||
import '../helper';
|
||||
|
||||
import { context, trace } from '@opentelemetry/api';
|
||||
|
||||
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
|
||||
import { loadOtel } from '../tracing';
|
||||
|
||||
const provider = loadOtel([
|
||||
new FetchInstrumentation({
|
||||
ignoreUrls: [/localhost:8090\/sockjs-node/],
|
||||
propagateTraceHeaderCorsUrls: [
|
||||
'https://cors-test.appspot.com/test',
|
||||
'https://httpbin.org/get',
|
||||
],
|
||||
clearTimingResources: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
const webTracerWithZone = provider.getTracer('example-tracer-web');
|
||||
|
||||
const getData = (url) => fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// example of keeping track of context between async operations
|
||||
const prepareClickEvent = () => {
|
||||
const url = 'https://httpbin.org/get';
|
||||
|
||||
const element = document.getElementById('button1');
|
||||
|
||||
const onClick = () => {
|
||||
const singleSpan = webTracerWithZone.startSpan(`files-series-info`);
|
||||
context.with(trace.setSpan(context.active(), singleSpan), () => {
|
||||
getData(url).then((_data) => {
|
||||
trace.getSpan(context.active()).addEvent('fetching-single-span-completed');
|
||||
singleSpan.end();
|
||||
}).finally(()=> {
|
||||
otel.OTELSeleniumDone();
|
||||
console.log(otel.memoryExporter.getFinishedSpans());
|
||||
});
|
||||
});
|
||||
};
|
||||
element.addEventListener('click', onClick);
|
||||
};
|
||||
|
||||
window.addEventListener('load', prepareClickEvent);
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* These are all needed to make otel to work correctly for IE
|
||||
*/
|
||||
window.__Zone_enable_cross_context_check = true;
|
||||
import 'babel-polyfill';
|
||||
import 'zone.js';
|
||||
|
||||
const safeStringify = require('fast-safe-stringify');
|
||||
|
||||
/**
|
||||
* Function to stringify data between browser and selenium
|
||||
* It works fine for circular dependency
|
||||
* @param obj
|
||||
* @return {*|string}
|
||||
* @constructor
|
||||
*/
|
||||
function JSONSafeStringify(obj) {
|
||||
return safeStringify(
|
||||
obj,
|
||||
function replacer(key, value) {
|
||||
// Remove the circular structure
|
||||
if (value === '[Circular]') {
|
||||
return;
|
||||
}
|
||||
return value;
|
||||
},
|
||||
2,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function helper to mark action on page as finished. This way selenium understands that test is finished
|
||||
*/
|
||||
function OTELSeleniumDone() {
|
||||
const element = document.createElement('div');
|
||||
element.setAttribute('id', 'otelSeleniumDone');
|
||||
element.innerHTML = 'OTELSeleniumDone';
|
||||
window.setTimeout(() => {
|
||||
document.body.appendChild(element);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
window.otel = Object.assign({}, window.otel, {
|
||||
JSONSafeStringify: JSONSafeStringify,
|
||||
OTELSeleniumDone: OTELSeleniumDone,
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
import { ConsoleSpanExporter, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
|
||||
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
|
||||
import { ZoneContextManager } from '@opentelemetry/context-zone-peer-dep';
|
||||
import { registerInstrumentations } from '@opentelemetry/instrumentation';
|
||||
|
||||
/**
|
||||
* Function helper to load the tracing with predefined instrumentations
|
||||
* @param instrumentations
|
||||
* @return {WebTracerProvider}
|
||||
*/
|
||||
export function loadOtel(instrumentations) {
|
||||
const provider = new WebTracerProvider();
|
||||
const memoryExporter = new InMemorySpanExporter();
|
||||
provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
|
||||
provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
|
||||
provider.register({
|
||||
contextManager: new ZoneContextManager(),
|
||||
});
|
||||
|
||||
registerInstrumentations({
|
||||
instrumentations: [
|
||||
instrumentations,
|
||||
],
|
||||
});
|
||||
window.otel = Object.assign({}, window.otel, {
|
||||
provider,
|
||||
memoryExporter,
|
||||
});
|
||||
return provider;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>XHR Plugin</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Example of using Web Tracer with XHR plugin and console exporter
|
||||
<script type="text/javascript" src="xhr.js"></script>
|
||||
<br/>
|
||||
<button id="button1">Test</button>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
'use strict';
|
||||
import '../helper';
|
||||
|
||||
import { context, trace } from '@opentelemetry/api';
|
||||
|
||||
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
|
||||
import { loadOtel } from '../tracing';
|
||||
|
||||
const provider = loadOtel([
|
||||
new XMLHttpRequestInstrumentation({
|
||||
ignoreUrls: [/localhost:8090\/sockjs-node/],
|
||||
propagateTraceHeaderCorsUrls: [
|
||||
'https://httpbin.org/get',
|
||||
],
|
||||
clearTimingResources: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
const webTracerWithZone = provider.getTracer('example-tracer-web');
|
||||
|
||||
const getData = (url) => new Promise((resolve, reject) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const req = new XMLHttpRequest();
|
||||
req.open('GET', url, true);
|
||||
req.setRequestHeader('Content-Type', 'application/json');
|
||||
req.setRequestHeader('Accept', 'application/json');
|
||||
req.onload = () => {
|
||||
resolve();
|
||||
};
|
||||
req.onerror = () => {
|
||||
reject();
|
||||
};
|
||||
req.send();
|
||||
});
|
||||
|
||||
// example of keeping track of context between async operations
|
||||
const prepareClickEvent = () => {
|
||||
const url = 'https://httpbin.org/get';
|
||||
|
||||
const element = document.getElementById('button1');
|
||||
|
||||
const onClick = () => {
|
||||
const singleSpan = webTracerWithZone.startSpan(`files-series-info`);
|
||||
context.with(trace.setSpan(context.active(), singleSpan), () => {
|
||||
getData(url).then((_data) => {
|
||||
trace.getSpan(context.active()).addEvent('fetching-single-span-completed');
|
||||
singleSpan.end();
|
||||
}).finally(() => {
|
||||
otel.OTELSeleniumDone();
|
||||
});
|
||||
});
|
||||
};
|
||||
element.addEventListener('click', onClick);
|
||||
};
|
||||
|
||||
window.addEventListener('load', prepareClickEvent);
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const Nightwatch = require('nightwatch');
|
||||
const browserstack = require('browserstack-local');
|
||||
require('dotenv').config();
|
||||
|
||||
let bs_local;
|
||||
|
||||
try {
|
||||
require.main.filename = './node_modules/.bin/nightwatch';
|
||||
// Code to start browserstack local before start of test
|
||||
console.log('Connecting local');
|
||||
Nightwatch.bs_local = bs_local = new browserstack.Local();
|
||||
bs_local.start({ key: process.env.BROWSERSTACK_KEY }, function (error) {
|
||||
if (error) {
|
||||
bs_local.stop(function () {});
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('Connected. Now testing...');
|
||||
Nightwatch.cli(function (argv) {
|
||||
Nightwatch.CliRunner(argv)
|
||||
.setup()
|
||||
.runTests()
|
||||
.catch((err) => {
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
// Code to stop browserstack local after end of single test
|
||||
bs_local.stop(function () {});
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (ex) {
|
||||
console.log('There was an error while starting the test runner:\n\n');
|
||||
process.stderr.write(ex.stack + '\n');
|
||||
process.exit(2);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
const TIMEOUT_ELEMENT_MS = 5000;
|
||||
|
||||
module.exports = {
|
||||
TIMEOUT_ELEMENT_MS,
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
const { TIMEOUT_ELEMENT_MS } = require('../../tests-helpers/constants');
|
||||
|
||||
module.exports = {
|
||||
'Fetch instrumentation': function (browser) {
|
||||
browser
|
||||
.url('http://localhost:8090/fetch')
|
||||
.waitForElementVisible('body', TIMEOUT_ELEMENT_MS)
|
||||
.waitForElementVisible('#button1', TIMEOUT_ELEMENT_MS)
|
||||
.click('#button1')
|
||||
.waitForElementVisible('#otelSeleniumDone', TIMEOUT_ELEMENT_MS)
|
||||
.execute(
|
||||
() => {
|
||||
const spans = otel.memoryExporter.getFinishedSpans();
|
||||
return otel.JSONSafeStringify(spans);
|
||||
},
|
||||
[],
|
||||
(result) => {
|
||||
const spans = JSON.parse(result.value);
|
||||
browser.assert.equal(spans.length, 2, 'Should export 2 spans');
|
||||
},
|
||||
)
|
||||
|
||||
browser.end(() => {
|
||||
console.log('end');
|
||||
});
|
||||
},
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
const { TIMEOUT_ELEMENT_MS } = require('../../tests-helpers/constants');
|
||||
module.exports = {
|
||||
'XHR instrumentation': function (browser) {
|
||||
browser
|
||||
.url('http://localhost:8090/xhr')
|
||||
.waitForElementVisible('body', TIMEOUT_ELEMENT_MS)
|
||||
.waitForElementVisible('#button1', TIMEOUT_ELEMENT_MS)
|
||||
.click('#button1')
|
||||
.waitForElementVisible('#otelSeleniumDone', TIMEOUT_ELEMENT_MS)
|
||||
.execute(
|
||||
function() {
|
||||
const spans = otel.memoryExporter.getFinishedSpans();
|
||||
return otel.JSONSafeStringify(spans);
|
||||
},
|
||||
[],
|
||||
function(result) {
|
||||
const spans = JSON.parse(result.value);
|
||||
browser.assert.equal(spans.length, 2, 'Should export 2 spans');
|
||||
},
|
||||
)
|
||||
|
||||
browser.end(() => {
|
||||
console.log('end');
|
||||
});
|
||||
},
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
const path = require('path');
|
||||
const directory = path.resolve(__dirname);
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
fetch: 'pages/fetch/index.js',
|
||||
xhr: 'pages/xhr/index.js',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js',
|
||||
sourceMapFilename: '[file].map',
|
||||
},
|
||||
target: ['web', 'es5'],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js[x]?$/,
|
||||
exclude: /(node_modules)/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
babelrc: false,
|
||||
configFile: path.resolve(__dirname, 'babel.config.js'),
|
||||
presets: ['@babel/preset-env'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
modules: [
|
||||
path.resolve(directory),
|
||||
'node_modules',
|
||||
],
|
||||
extensions: ['.ts', '.js', '.jsx', '.json'],
|
||||
},
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
const webpack = require('webpack');
|
||||
const webpackMerge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
|
||||
const directory = path.resolve(__dirname);
|
||||
|
||||
const common = {
|
||||
mode: 'development',
|
||||
entry: {
|
||||
fetch: 'pages/fetch/index.js',
|
||||
// xhr: 'pages/xhr/index.js',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js',
|
||||
sourceMapFilename: '[file].map',
|
||||
},
|
||||
target: 'web',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js[x]?$/,
|
||||
exclude: /(node_modules)/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
babelrc: false,
|
||||
configFile: path.resolve(__dirname, 'babel.config.js'),
|
||||
presets: ['@babel/preset-env'],
|
||||
},
|
||||
},
|
||||
include: [
|
||||
path.resolve(__dirname, 'pages/helper.js'),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
modules: [
|
||||
path.resolve(directory),
|
||||
'node_modules',
|
||||
],
|
||||
extensions: ['.js', '.jsx', '.json'],
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = webpackMerge(common, {
|
||||
devtool: 'eval-source-map',
|
||||
devServer: {
|
||||
static: path.resolve(__dirname),
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('development'),
|
||||
}),
|
||||
],
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
// devtool: 'inline-source-map',
|
||||
devServer: {
|
||||
static: path.resolve(__dirname, 'pages'),
|
||||
},
|
||||
});
|
|
@ -0,0 +1,17 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [new TerserPlugin({
|
||||
extractComments: false,
|
||||
terserOptions: {
|
||||
ie8: true,
|
||||
safari10: true,
|
||||
},
|
||||
})],
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue