Skip to content

Commit

Permalink
feat: adding e2e tests to the sdk
Browse files Browse the repository at this point in the history
This PR adds End-to-end tests to the SDK.

Closes: https://topsort.atlassian.net/browse/API-922
  • Loading branch information
barbmarcio authored Jul 25, 2024
1 parent 1d13410 commit 6668565
Show file tree
Hide file tree
Showing 16 changed files with 302 additions and 4 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SERVER_PORT=
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.env

coverage/
dist/
node_modules/
test-results/
test-results.json
23 changes: 23 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ We'd love to accept your patches and contributions to this project. Bellow, you
- [Building the SDK](#building-the-sdk)
- [Tests](#tests)
- [Unit Tests](#unit-tests)
- [E2E Tests](#e2e-tests)
- [Code Standards](#code-standards)
- [Submitting contributions](#submitting-contributions)
- [Commit Messages](#commit-messages)
Expand Down Expand Up @@ -94,6 +95,24 @@ To run the unit tests, use the following command:
bun run test
```

### E2E Tests

By default, the application is set to serve a web browser in the port `8080` for Playwright. If this port is already being used on your local machine, make sure you change the port in your `.env`.`SERVER_PORT`.
To run the end-to-end tests, make sure you have installed the browsers supported by playwright by running this command:

```bash
npx playwright install
```

Please refer to [Playwright Documentation](https://playwright.dev/docs/browsers) for details.

Then, also make sure you have the latest bundled files before running it. Use the following commands:

```bash
bun run build
bun run test:e2e
```

## Code Standards

We follow the coding standards set by Biome. Ensure your code follows these guidelines before submitting a pull request. You can run the formatter with the following command:
Expand Down Expand Up @@ -125,6 +144,10 @@ We do conventional commits, so it will fail on checker with capital case after c
The SDK uses following configuration files:
- `tsconfig.json`: TypeScript configuration.
- `tsup.config.ts`: Configuration for the TSUP bundler.
- `playwright.config.ts`: Configuration for E2E tests runner

We also have the following variables as part of the `.env` file:
- `PLAYWRIGHT_PORT`: Port used to run the local web browser to run Playwright E2E tests.

## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ reportEvent(config, event)
400:
```json
{
"status": 204,
"status": 400,
"statusText": "No Content",
"body": {
"errCode": "bad_request",
Expand Down
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[test]
coverage = true
root = "./test"
95 changes: 95 additions & 0 deletions e2e/auctions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { expect, test } from "@playwright/test";
import { apis, baseURL } from "../src/constants/apis.constant";
import { playwrightConstants } from "./config";

test.describe("Create Auction via Topsort SDK", () => {
test("should create an auction successfully", async ({ page }) => {
const mockAPIResponse = {
results: [
{
resultType: "listings",
winners: [],
error: false,
},
{
resultType: "banners",
winners: [],
error: false,
},
],
};

await page.route(`${baseURL}/${apis.auctions}`, async (route) => {
await route.fulfill({ json: mockAPIResponse });
});

await page.goto(playwrightConstants.host);
const result = await page.evaluate(() => {
const config = {
apiKey: "rando-api-key",
};

const auctionDetails = {
auctions: [
{
type: "listings",
slots: 3,
category: { id: "cat123" },
geoTargeting: { location: "US" },
},
{
type: "banners",
slots: 1,
device: "desktop",
slotId: "slot123",
category: { ids: ["cat1", "cat2"] },
geoTargeting: { location: "UK" },
},
],
};
if (typeof window.sdk.createAuction === "undefined") {
throw new Error("Global function `createAuction` is not available.");
}

return window.sdk.createAuction(config, auctionDetails);
});

expect(result).toEqual(mockAPIResponse);
});

test("should fail to call with missing apiKey", async ({ page }) => {
const expectedError = { status: 401, statusText: "API Key is required.", body: {} };
await page.goto(playwrightConstants.host);
const result = await page.evaluate(() => {
const config = {
apiKey: null,
};

const auctionDetails = {
auctions: [
{
type: "listings",
slots: 3,
category: { id: "cat123" },
geoTargeting: { location: "US" },
},
{
type: "banners",
slots: 1,
device: "desktop",
slotId: "slot123",
category: { ids: ["cat1", "cat2"] },
geoTargeting: { location: "UK" },
},
],
};
if (typeof window.sdk.createAuction === "undefined") {
throw new Error("Global function `createAuction` is not available.");
}

return window.sdk.createAuction(config, auctionDetails);
});

expect(result).toEqual(expectedError);
});
});
3 changes: 3 additions & 0 deletions e2e/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const playwrightConstants = {
host: `http://localhost:${process.env.SERVER_PORT || 8080}/index.html`,
};
77 changes: 77 additions & 0 deletions e2e/events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { expect, test } from "@playwright/test";
import { apis, baseURL } from "../src/constants/apis.constant";
import { playwrightConstants } from "./config";

test.describe("Report Events via Topsort SDK", () => {
test("should report an successfully", async ({ page }) => {
const mockAPIResponse = {
ok: true,
};

await page.route(`${baseURL}/${apis.events}`, async (route) => {
await route.fulfill({ json: mockAPIResponse });
});

await page.goto(playwrightConstants.host);
const result = await page.evaluate(() => {
const config = {
apiKey: "rando-api-key",
};

const event = {
impressions: [
{
resolvedBidId:
"ChAGaP5D2ex-UKEEBCOHwvDjEhABkF4FDAx0S5mMD2cOG0w9GhABkEnL2CB6qKIoqeItVgA_InsKd2h0dHBzOi8vd3d3LndlYmEuYmUvZnIvcHJvbW8uaHRtbD91dG1fc291cmNlPW15c2hvcGkmdXRtX21lZGl1bT1iYW5uZXJfMTI4MHg0MDAmdXRtX2NvbnRlbnQ9ZGlzcGxheSZ1dG1fY2FtcGFpZ249c29sZGVuEAU",
id: "1720706109.713344-53B92988-7A49-4679-B18E-465943B46149",
occurredAt: "2024-07-11T13:55:09Z",
opaqueUserId: "38e0a5ff-9f8a-4e80-8969-e5e3f01348e8",
placement: {
path: "/categories/sports",
},
},
],
};

if (typeof window.sdk.reportEvent === "undefined") {
throw new Error("Global function `reportEvent` is not available.");
}

return window.sdk.reportEvent(config, event);
});

expect(result).toEqual(mockAPIResponse);
});

test("should fail to call with missing apiKey", async ({ page }) => {
const expectedError = { status: 401, statusText: "API Key is required.", body: {} };
await page.goto(playwrightConstants.host);
const result = await page.evaluate(() => {
const config = {
apiKey: null,
};

const event = {
impressions: [
{
resolvedBidId:
"ChAGaP5D2ex-UKEEBCOHwvDjEhABkF4FDAx0S5mMD2cOG0w9GhABkEnL2CB6qKIoqeItVgA_InsKd2h0dHBzOi8vd3d3LndlYmEuYmUvZnIvcHJvbW8uaHRtbD91dG1fc291cmNlPW15c2hvcGkmdXRtX21lZGl1bT1iYW5uZXJfMTI4MHg0MDAmdXRtX2NvbnRlbnQ9ZGlzcGxheSZ1dG1fY2FtcGFpZ249c29sZGVuEAU",
id: "1720706109.713344-53B92988-7A49-4679-B18E-465943B46149",
occurredAt: "2024-07-11T13:55:09Z",
opaqueUserId: "38e0a5ff-9f8a-4e80-8969-e5e3f01348e8",
placement: {
path: "/categories/sports",
},
},
],
};
if (typeof window.sdk.reportEvent === "undefined") {
throw new Error("Global function `reportEvent` is not available.");
}

return window.sdk.reportEvent(config, event);
});

expect(result).toEqual(expectedError);
});
});
30 changes: 30 additions & 0 deletions e2e/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Topsort SDK Test Application</title>
<script src="./index.global.js"></script>
</head>
<body>
<h1>Test Topsort.js Integration</h1>
<script>
window.sdk = {
createAuction: async (config, auctionDetails) => {
const result = await Topsort.createAuction(
config,
auctionDetails
).catch((error) => error);
return result;
},
reportEvent: async (config, eventDetails) => {
const result = await Topsort.reportEvent(
config,
eventDetails
).catch((error) => error);
return result;
},
};
</script>
</body>
</html>
22 changes: 22 additions & 0 deletions e2e/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { file } from "bun";

const PORT = process.env.SERVER_PORT || 8080;

Bun.serve({
fetch(req) {
const url = new URL(req.url);
const pathname = url.pathname === "/" ? "/index.html" : url.pathname;
const filePath = `./dist${pathname}`;

try {
if (filePath.endsWith(".ico")) {
return new Response("", { status: 204 });
}

return new Response(file(filePath));
} catch (e) {
return new Response("Not Found", { status: 404 });
}
},
port: PORT,
});
6 changes: 6 additions & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
interface Window {
sdk: {
createAuction: (a, b) => unknown;
reportEvent: (a, b) => unknown;
};
}
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@
],
"scripts": {
"build": "tsup",
"test:e2e": "playwright test",
"format": "biome check",
"format:fix": "biome check --write",
"prepare": "lefthook install"
"prepare": "lefthook install",
"serve:e2e": "bun run ./e2e/server.ts"
},
"devDependencies": {
"@biomejs/biome": "1.8.3",
"@playwright/test": "^1.45.2",
"@types/bun": "1.1.6",
"lefthook": "1.7.5",
"msw": "2.3.2",
Expand Down
31 changes: 31 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
testDir: "./e2e",
timeout: 30000,
retries: 0,
reporter: [["list"], ["json", { outputFile: "test-results.json" }]],
use: {
trace: "on-first-retry",
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
},
],
webServer: {
command: "bun run serve:e2e",
reuseExistingServer: !process.env.CI,
stdout: "ignore",
stderr: "pipe",
},
});
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
"allowJs": true,
"types": ["node"]
},
"include": ["src/*.ts", "src/**/*.ts"],
"include": ["src/*.ts", "src/**/*.ts", "e2e/server.ts"],
"exclude": ["node_modules"]
}
4 changes: 3 additions & 1 deletion tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { defineConfig } from "tsup";

export default defineConfig({
entry: ["src/index.ts"],
format: ["cjs", "esm"],
format: ["cjs", "esm", "iife"],
dts: true,
clean: true,
minify: true,
esbuildOptions(options) {
options.keepNames = true;
options.globalName = "Topsort";
},
onSuccess: "cp -r ./e2e/public/* dist",
});

0 comments on commit 6668565

Please sign in to comment.