diff --git a/examples/setup-of-tracetest-tests/.gitignore b/examples/setup-of-tracetest-tests/.gitignore new file mode 100644 index 0000000000..8f00ef2307 --- /dev/null +++ b/examples/setup-of-tracetest-tests/.gitignore @@ -0,0 +1,3 @@ +node_modules +.env +dist \ No newline at end of file diff --git a/examples/setup-of-tracetest-tests/README.md b/examples/setup-of-tracetest-tests/README.md new file mode 100644 index 0000000000..bf97609d4d --- /dev/null +++ b/examples/setup-of-tracetest-tests/README.md @@ -0,0 +1,9 @@ +# Setup and Tear Down of Tracetest Tests + +> Read the detailed blog post [Enabling Programatic Setup and Tear Down of Tracetest Tests](https://tracetest.io/blog/enabling-programatic-setup-and-tear-down-of-tracetest-tests) that describes two methods to run setup steps before executing a test: +- via a test suite +- via the @tracetest/client NPM package + +The article contains the complete instructions on how to run this example. + +Feel free to check out the [docs](https://docs.tracetest.io/), and join our [Slack Community](https://dub.sh/tracetest-community) for more info! \ No newline at end of file diff --git a/examples/setup-of-tracetest-tests/delete_pokemon.yaml b/examples/setup-of-tracetest-tests/delete_pokemon.yaml new file mode 100644 index 0000000000..25118c751c --- /dev/null +++ b/examples/setup-of-tracetest-tests/delete_pokemon.yaml @@ -0,0 +1,29 @@ +type: Test +spec: + id: delete-pokemon + name: Delete Pokemon + trigger: + type: http + httpRequest: + method: DELETE + url: https://demo-pokeshop.tracetest.io/pokemon/${env:pokemon_id} + headers: + - key: Content-Type + value: application/json + specs: + - selector: span[tracetest.span.type="general" name="Tracetest trigger"] + name: Delete returns a 200 status code + assertions: + - attr:tracetest.response.status = 200 + - selector: span[tracetest.span.type="database" db.system="redis" db.operation="del" db.redis.database_index="0"] + name: Ensure we are deleting from the redis cache also + assertions: + - attr:tracetest.selected_spans.count = 1 + - selector: span[tracetest.span.type="database"] + name: "All Database Spans: Processing time is less than 10ms" + assertions: + - attr:tracetest.span.duration < 10ms + - selector: span[tracetest.span.type="database" name="delete pokeshop.pokemon" db.system="postgres" db.name="pokeshop" db.user="ashketchum" db.operation="delete" db.sql.table="pokemon"] + name: Check that number of deleted rows from Postgres is one + assertions: + - attr:db.result = 1 diff --git a/examples/setup-of-tracetest-tests/delete_test.ts b/examples/setup-of-tracetest-tests/delete_test.ts new file mode 100644 index 0000000000..8f9c80721d --- /dev/null +++ b/examples/setup-of-tracetest-tests/delete_test.ts @@ -0,0 +1,69 @@ + +import fs from 'fs'; +import { Pokemon } from './types'; +import Tracetest from '@tracetest/client'; + +// To use the @tracetest/client, you must have a token for the environment. This is created on the Settings +// page under Tokens by the administrator for the environment. The token below has been given the 'engineer' +// role in the pokeshop-demo env in the tracetest-demo org so you can create and run tests in this environment. +// Want to read more about setting up tokens? https://docs.tracetest.io/concepts/environment-tokens + +const TRACETEST_API_TOKEN = 'tttoken_4fea89f6e7fa1500'; +const baseUrl = 'https://demo-pokeshop.tracetest.io/pokemon'; + +// json for the body of the POST to create a pokemon +const setupPokemon = `{ + "name": "fearow", + "imageUrl": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/22.png", + "isFeatured": false, + "type": "normal,flying" +}` + +const main = async () => { + console.log('Lets use the TRACETEST_API_TOKEN to authenticate the @tracetest/client module...') + const tracetest = await Tracetest(TRACETEST_API_TOKEN); + + + //execute setup by adding a Pokemon with a REST POST api call directly + const createPokemon = async (): Promise => { + const response = await fetch(baseUrl,{ + method: 'POST', + body: setupPokemon, + headers: {'Content-Type': 'application/json'} + }); + return await response.json() as Pokemon; + }; + + console.log('Adding the Pokemon - this is the setup action we need before running a Tracetest test') + const pokemon = await createPokemon(); + + // Get the id of the pokemon that we created in the setup step + let pokemonId = pokemon.id; + console.log('The Pokemon id we created was ', pokemonId); + + + // Lets pull in the delete-pokemon test from a file + let deleteTest = fs.readFileSync('delete_pokemon.yaml', 'utf-8'); + + // Lets setup the variables we will be passing into the test (ie the pokemon_id) + const getVariables = (id: string) => [ + { key: 'pokemon_id', value: id } + ]; + + const deletePokemon = async () => { + console.log('Creating the delete-pokemon test based on the test in delete_pokemon.yaml...'); + const test = await tracetest.newTest(deleteTest); + + + // run deletes pokemon test + console.log('Running the delete-pokemon test...'); + const run = await tracetest.runTest(test, { variables: getVariables(String(pokemonId)) }); + await run.wait(); + }; + + await deletePokemon(); + + console.log(await tracetest.getSummary()); +}; + +main(); diff --git a/examples/setup-of-tracetest-tests/delete_test_suite.yaml b/examples/setup-of-tracetest-tests/delete_test_suite.yaml new file mode 100644 index 0000000000..3045167f67 --- /dev/null +++ b/examples/setup-of-tracetest-tests/delete_test_suite.yaml @@ -0,0 +1,8 @@ +type: TestSuite +spec: + id: bS4cix2IR + name: Delete with Setup + description: A test of the deletion end point with setup test which adds the pokemon as a setup step. + steps: + - setup-pokemon + - delete-pokemon diff --git a/examples/setup-of-tracetest-tests/package-lock.json b/examples/setup-of-tracetest-tests/package-lock.json new file mode 100644 index 0000000000..4c55a2451d --- /dev/null +++ b/examples/setup-of-tracetest-tests/package-lock.json @@ -0,0 +1,309 @@ +{ + "name": "test-setup", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "test-setup", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@tracetest/client": "^0.0.27" + }, + "devDependencies": { + "@types/node": "^20.11.17", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", + "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==", + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.21.0.tgz", + "integrity": "sha512-KP+OIweb3wYoP7qTYL/j5IpOlu52uxBv5M4+QhSmmUfLyTgu1OIS71msK3chFo1D6Y61BIH3wMiMYRCxJCQctA==", + "peer": true, + "dependencies": { + "@opentelemetry/semantic-conventions": "1.21.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.21.0.tgz", + "integrity": "sha512-1Z86FUxPKL6zWVy2LdhueEGl9AHDJcx+bvHStxomruz6Whd02mE3lNUMjVJ+FGRoktx/xYQcxccYb03DiUP6Yw==", + "peer": true, + "dependencies": { + "@opentelemetry/core": "1.21.0", + "@opentelemetry/semantic-conventions": "1.21.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.21.0.tgz", + "integrity": "sha512-yrElGX5Fv0umzp8Nxpta/XqU71+jCAyaLk34GmBzNcrW43nqbrqvdPs4gj4MVy/HcTjr6hifCDCYA3rMkajxxA==", + "peer": true, + "dependencies": { + "@opentelemetry/core": "1.21.0", + "@opentelemetry/resources": "1.21.0", + "@opentelemetry/semantic-conventions": "1.21.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.21.0.tgz", + "integrity": "sha512-lkC8kZYntxVKr7b8xmjCVUgE0a8xgDakPyDo9uSWavXPyYqLgYYGdEd2j8NxihRyb6UwpX3G/hFUF4/9q2V+/g==", + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tracetest/client": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/@tracetest/client/-/client-0.0.27.tgz", + "integrity": "sha512-JNO7AjPGoFie+egYyr7ZZgNVw9X59PIBvvMuhifd0Ofl1JOlXkPtXTM5WgocToZ6Pnmuk/zQEdVanFRt7r886g==", + "dependencies": { + "js-yaml": "^4.1.0" + }, + "peerDependencies": { + "@opentelemetry/sdk-trace-base": "^1.18.1" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", + "integrity": "sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + } +} diff --git a/examples/setup-of-tracetest-tests/package.json b/examples/setup-of-tracetest-tests/package.json new file mode 100644 index 0000000000..8ef6505759 --- /dev/null +++ b/examples/setup-of-tracetest-tests/package.json @@ -0,0 +1,25 @@ +{ + "name": "test-setup", + "version": "1.0.0", + "description": "", + "main": "delete_test.ts", + "scripts": { + "build": "tsc", + "start": "ts-node delete_test" + }, + "keywords": [ + "tracetest", + "typescript", + "@tracetest/core" + ], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/node": "^20.11.17", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + }, + "dependencies": { + "@tracetest/client": "^0.0.27" + } +} diff --git a/examples/setup-of-tracetest-tests/setup_pokemon.yaml b/examples/setup-of-tracetest-tests/setup_pokemon.yaml new file mode 100644 index 0000000000..6c88e79988 --- /dev/null +++ b/examples/setup-of-tracetest-tests/setup_pokemon.yaml @@ -0,0 +1,26 @@ +type: Test +spec: + id: setup-pokemon + name: Setup Pokemon + trigger: + type: http + httpRequest: + method: POST + url: https://demo-pokeshop.tracetest.io/pokemon + body: "{\n \"name\": \"fearow\",\n \"type\":\"normal,flying\",\n \"imageUrl\":\"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/22.png\",\n \"isFeatured\": false\n}\n" + headers: + - key: Content-Type + value: application/json + specs: + - selector: span[tracetest.span.type="general" name="Tracetest trigger"] + name: Check to see the post worked + assertions: + - attr:tracetest.response.status = 201 + outputs: + - name: pokemon_id + selector: span[tracetest.span.type="general" name="Tracetest trigger"] + value: attr:tracetest.response.body| json_path '$.id' + skipTraceCollection: true + + + \ No newline at end of file diff --git a/examples/setup-of-tracetest-tests/tsconfig.json b/examples/setup-of-tracetest-tests/tsconfig.json new file mode 100644 index 0000000000..0f291f03fd --- /dev/null +++ b/examples/setup-of-tracetest-tests/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "outDir": "./dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } + } \ No newline at end of file diff --git a/examples/setup-of-tracetest-tests/types.ts b/examples/setup-of-tracetest-tests/types.ts new file mode 100644 index 0000000000..1d2223bc3f --- /dev/null +++ b/examples/setup-of-tracetest-tests/types.ts @@ -0,0 +1,9 @@ +// type definition needed for the json returned from creating a new pokemon + +export type Pokemon = { + id: number; + imageUrl: string; + isFeatured: boolean; + type: string; + name: string; + }; \ No newline at end of file