Skip to content
Open
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
26 changes: 26 additions & 0 deletions e2e/core/mocks/transport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type {
Transport,
TransportRequest,
TransportResponse
} from "@trackjs/core";

// Mock transport for testing
export class MockTransport implements Transport {
public sentRequests: TransportRequest[] = [];
public shouldFail = false;

async send(request: TransportRequest): Promise<TransportResponse> {
if (this.shouldFail) {
throw new Error("Transport error");
}
this.sentRequests.push(request);
return {
status: 200
};
}

reset() {
this.sentRequests = [];
this.shouldFail = false;
}
}
86 changes: 0 additions & 86 deletions e2e/core/node-compatibility.test.ts

This file was deleted.

129 changes: 129 additions & 0 deletions e2e/core/node-integration.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/**
* Test integration with the NodeJS environment with plain JavaScript.
* Focused on sending objects that typescript would not allow
*/

import { test, expect, beforeEach } from "vitest";
import { TrackJS, timestamp } from "@trackjs/core";
import { MockTransport } from "./mocks/transport";

beforeEach(() => {
TrackJS.destroy();
});

test("TrackJS basic functionality", () => {
const transport = new MockTransport();

TrackJS.initialize({
token: "test-token",
transport
});

TrackJS.addMetadata({
"foo": "bar"
});

TrackJS.addTelemetry("con", {
timestamp: timestamp(),
severity: "info",
message: "test message"
});

const networkTelemetry = {
type: "fetch",
startedOn: timestamp(),
method: "POST",
url: "https://example.com/path"
};
TrackJS.addTelemetry("net", networkTelemetry);
networkTelemetry.completedOn = timestamp();
networkTelemetry.statusCode = 403;
networkTelemetry.statusText = "Forbidden";

TrackJS.track(new Error("oops"), {
entry: "catch",
metadata: {
"bar": "baz"
}
});

expect(transport.sentRequests.length).toBe(1);
expect(JSON.parse(transport.sentRequests[0].data)).toMatchObject({
entry: "catch",
message: "oops",
stack: expect.any(String),
metadata: [
{ key: "foo", value: "bar"},
{ key: "bar", value: "baz" }
],
console: [
{
timestamp: expect.any(String),
severity: "info",
message: "test message",
}
],
network: [
{
type: "fetch",
startedOn: expect.any(String),
method: "POST",
url: "https://example.com/path",
completedOn: expect.any(String),
statusCode: 403,
statusText: "Forbidden"
}
]
});
});

test("TrackJS with missing token", () => {
expect(() => TrackJS.initialize()).toThrowError("TrackJS token is required");
});

test("TrackJS double initialized", () => {
expect(() => TrackJS.initialize({ token: "test-token" })).not.toThrowError();
expect(() => TrackJS.initialize({ token: "test-token" })).toThrowError("TrackJS is already initialized");
});

test("TrackJS.addMetadata with non-strings", () => {
const transport = new MockTransport();
TrackJS.initialize({ token: "test-token", transport });
TrackJS.addMetadata({
[Symbol("test")]: { "foo": "bar" },
42: false
});
TrackJS.track("test");
expect(JSON.parse(transport.sentRequests[0].data)).toMatchObject({
metadata: [
{ key: "42", value: "false" }
]
});
});

test("TrackJS.addTelemetry with invalid shape", () => {
const transport = new MockTransport();
TrackJS.initialize({ token: "test-token", transport });

// add console with wrong type key
expect(() => {
TrackJS.addTelemetry("net", {
timestamp: timestamp(),
severity: "log",
message: "test message"
});
}).toThrow();

// add garbage to console
expect(() => {
TrackJS.addTelemetry("con", {
foo: "bar"
});
}).toThrow();

TrackJS.track("test");
expect(JSON.parse(transport.sentRequests[0].data)).toMatchObject({
console: [],
network: []
});
});
125 changes: 125 additions & 0 deletions e2e/core/node-integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { TrackJS, timestamp } from "@trackjs/core";
import { test, expect, beforeEach } from "vitest";
import { MockTransport } from "./mocks/transport";
import type { NetworkTelemetry, Transport, TransportRequest, TransportResponse } from "@trackjs/core";

beforeEach(() => {
TrackJS.destroy();
});

test('TrackJS.install({...}) with minimum options', () => {
TrackJS.initialize({
token: "test-token",
});
expect(TrackJS.isInitialized()).toBe(true);
});

test('TrackJS.track() can track errors after install', async () => {
const transport = new MockTransport();

TrackJS.initialize({
token: 'test-token',
transport
});

// Track different error types
await TrackJS.track('String error');
await TrackJS.track(new Error('Error'));
await TrackJS.track({ custom: 'object' });

// Verify requests were sent
expect(transport.sentRequests).toHaveLength(3);

// Verify the structure of a request
const firstRequest = transport.sentRequests[0] as TransportRequest;
expect(firstRequest.method).toBe('POST');
expect(firstRequest.url).toBe('https://capture.trackjs.com/capture/node?token=test-token&v=core-0.0.0');

expect(JSON.parse(firstRequest.data as string)).toMatchObject({
message: '"String error"',
stack: expect.any(String)
});
expect(JSON.parse(transport.sentRequests[1]?.data as string)).toMatchObject({
message: 'Error',
stack: expect.any(String)
});
expect(JSON.parse(transport.sentRequests[2]?.data as string)).toMatchObject({
message: '{"custom":"object"}',
stack: expect.any(String)
});
});

test('TrackJS.track() with custom metadata', async () => {
const transport = new MockTransport();

TrackJS.initialize({
token: 'test token',
transport,
metadata: {
"foo": "bar"
}
});

await TrackJS.track(new Error('Oops'), { metadata: { "bar": "baz" }});

expect(transport.sentRequests).toHaveLength(1);
expect(JSON.parse(transport.sentRequests[0]?.data as string)).toMatchObject({
metadata: [
{ key: "foo", value: "bar" },
{ key: "bar", value: "baz" }
]
});
})

test('TrackJS.addTelemetry(...) sends telemetry', async () => {
const transport = new MockTransport();

TrackJS.initialize({
token: 'test token',
transport
});

TrackJS.addTelemetry("con", {
timestamp: timestamp(),
severity: "info",
message: "test message"
});

let networkTelemetry: NetworkTelemetry = {
type: "fetch",
method: "POST",
url: "https://example.com/path",
startedOn: timestamp()
};

TrackJS.addTelemetry("net", networkTelemetry);

networkTelemetry.completedOn = timestamp();
networkTelemetry.statusCode = 404;
networkTelemetry.statusText = "NOT FOUND";

await TrackJS.track(new Error('Oops'));

expect(transport.sentRequests).toHaveLength(1);
expect(JSON.parse(transport.sentRequests[0]?.data as string)).toMatchObject({
console: [
{
timestamp: expect.any(String),
severity: "info",
message: "test message"
}
],
network: [
{
type: "fetch",
method: "POST",
url: "https://example.com/path",
startedOn: expect.any(String),
completedOn: expect.any(String),
statusCode: 404,
statusText: "NOT FOUND"
}
]
});
});

3 changes: 2 additions & 1 deletion e2e/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"private": true,
"type": "module",
"scripts": {
"test": "vitest run"
"test": "vitest run",
"test:watch": "vitest"
},
"dependencies": {
"@trackjs/core": "file:../../packages/core"
Expand Down
Loading