diff --git a/.env.example b/.env.example
index 0d0e8def04..9dba2e3707 100644
--- a/.env.example
+++ b/.env.example
@@ -57,6 +57,8 @@ LOG_LEVEL=info
#
###############################################################################
+TZ=UTC
+
# Configure where integrations will be loaded from
NANGO_INTEGRATIONS_FULL_PATH=
diff --git a/packages/shared/lib/services/sync/data/records.service.integration.test.ts b/packages/shared/lib/services/sync/data/records.service.integration.test.ts
index 539676be8e..430dfeacec 100644
--- a/packages/shared/lib/services/sync/data/records.service.integration.test.ts
+++ b/packages/shared/lib/services/sync/data/records.service.integration.test.ts
@@ -25,10 +25,9 @@ describe('Records service', () => {
expect(success).toBe(true);
expect(error).toBe(null);
expect(response?.records.length).toBe(n);
- const timestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{5,6}\+\d{2}:\d{2}$/;
expect(response?.records[0]?.['_nango_metadata']).toMatchObject({
- first_seen_at: expect.stringMatching(timestampRegex),
- last_modified_at: expect.stringMatching(timestampRegex),
+ first_seen_at: expect.toBeIsoDateTimezone(),
+ last_modified_at: expect.toBeIsoDateTimezone(),
last_action: 'ADDED',
deleted_at: null,
cursor: expect.stringMatching(/^[A-Za-z0-9+/]+={0,2}$/) // base64 encoded string
diff --git a/packages/shared/lib/vitest.d.ts b/packages/shared/lib/vitest.d.ts
new file mode 100644
index 0000000000..55290dadb4
--- /dev/null
+++ b/packages/shared/lib/vitest.d.ts
@@ -0,0 +1,14 @@
+export * from 'vitest';
+
+/* eslint-disable @typescript-eslint/no-empty-interface */
+interface CustomMatchers
{
+ toBeIsoDate: () => TR;
+ toBeIsoDateTimezone: () => TR;
+ toBeUUID: () => TR;
+}
+
+declare module 'vitest' {
+ export interface Assertion extends CustomMatchers {}
+ export interface AsymmetricMatchersContaining extends CustomMatchers {}
+ export interface ExpectStatic extends CustomMatchers {}
+}
diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json
index 41b9c5a4f3..d2f585f7ef 100644
--- a/packages/shared/tsconfig.json
+++ b/packages/shared/tsconfig.json
@@ -4,6 +4,10 @@
"rootDir": ".",
"outDir": "dist"
},
- "references": [{ "path": "../node-client" }],
+ "references": [
+ {
+ "path": "../node-client"
+ }
+ ],
"include": ["lib/**/*"]
}
diff --git a/tests/setupFiles.ts b/tests/setupFiles.ts
new file mode 100644
index 0000000000..bceed8e6cf
--- /dev/null
+++ b/tests/setupFiles.ts
@@ -0,0 +1,43 @@
+import { expect } from 'vitest';
+
+const dateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{1,6}Z$/;
+const dateRegexWithTZ = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{1,6}\+\d{2}:\d{2}$/;
+const uuidRegex = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
+
+expect.extend({
+ toBeIsoDate: (received: any) => {
+ if (received instanceof Date) {
+ return { pass: true, message: () => '' };
+ } else if (typeof received === 'string' && dateRegex.test(received)) {
+ return { pass: true, message: () => '' };
+ }
+
+ return {
+ message: () => `expected ${received} to be an ISO Date`,
+ pass: false
+ };
+ },
+
+ toBeIsoDateTimezone: (received: any) => {
+ if (received instanceof Date) {
+ return { pass: true, message: () => '' };
+ } else if (typeof received === 'string' && dateRegexWithTZ.test(received)) {
+ return { pass: true, message: () => '' };
+ }
+
+ return {
+ message: () => `expected ${received} to be an ISO Date`,
+ pass: false
+ };
+ },
+
+ toBeUUID: (received: any) => {
+ if (!uuidRegex.test(received)) {
+ return {
+ message: () => `expected ${received} to be a UUID v4`,
+ pass: false
+ };
+ }
+ return { pass: true, message: () => '' };
+ }
+});
diff --git a/vite.integration.config.ts b/vite.integration.config.ts
index d2a1c279ce..bed8c12869 100644
--- a/vite.integration.config.ts
+++ b/vite.integration.config.ts
@@ -1,13 +1,15 @@
///
-
// Configure Vitest (https://vitest.dev/config/)
import { defineConfig } from 'vite';
+process.env.TZ = 'UTC';
+
export default defineConfig({
test: {
include: ['**/*.integration.{test,spec}.?(c|m)[jt]s?(x)'],
globalSetup: './tests/setup.ts',
+ setupFiles: './tests/setupFiles.ts',
threads: false,
testTimeout: 20000
}