Skip to content

Commit

Permalink
test: Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
trevormunoz committed Aug 16, 2024
1 parent 2a4ae02 commit bc4d84f
Show file tree
Hide file tree
Showing 7 changed files with 5,543 additions and 4 deletions.
12 changes: 8 additions & 4 deletions deno.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
{
"$schema": "https://deno.land/x/deno/cli/schemas/config-file.v1.json",
"imports": {
"std/fmt/colors": "https://deno.land/[email protected]/fmt/colors.ts",
"@std/assert": "jsr:@std/assert@1",
"@std/testing/mock": "jsr:@std/testing/mock",
"@std/testing/bdd": "jsr:@std/testing/bdd",
"sleep": "https://deno.land/x/[email protected]/mod.ts",
"std/flags": "https://deno.land/[email protected]/flags/mod.ts",
"std/path": "https://deno.land/[email protected]/path/mod.ts",
"std/fmt/colors": "https://deno.land/[email protected]/fmt/colors.ts",
"std/fs": "https://deno.land/[email protected]/fs/mod.ts",
"sleep": "https://deno.land/x/[email protected]/mod.ts"
"std/path": "https://deno.land/[email protected]/path/mod.ts"
},
"tasks": {
"run": "deno run --watch --allow-env=AIRTABLE_BASE_ID,AIRTABLE_API_KEY --allow-net=api.airtable.com --allow-read=.env,./dist/data/raw --allow-write=. ./src/main.ts --backup"
"run": "deno run --watch --allow-env=AIRTABLE_BASE_ID,AIRTABLE_API_KEY --allow-net=api.airtable.com --allow-read=.env,./dist/data/raw --allow-write=. ./src/main.ts --backup",
"test": "deno test --allow-read=./tests/ "
}
}
31 changes: 31 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tests/fixtures/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as itemData } from "./responses/items_response_2024-08-15.json" assert { type: "json" };
5 changes: 5 additions & 0 deletions tests/fixtures/requests/items_request.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GET https://api.airtable.com/v0/{{AIRTABLE_BASE_ID}}/Items
Content-Type: application/json
User-Agent: curl/7.64.1
Authorization: Bearer {{AIRTABLE_API_KEY}}

5,385 changes: 5,385 additions & 0 deletions tests/fixtures/responses/items_response_2024-08-15.json

Large diffs are not rendered by default.

59 changes: 59 additions & 0 deletions tests/getAirtableData.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { describe, it, beforeEach, afterEach } from "@std/testing/bdd";
import { assertEquals, assertExists } from "@std/assert";
import { createFetchStubImplementation } from "./mocks/fetchStub.ts";
import { getAirtableData } from "../src/main.ts";
import { itemData as mockItemData } from "./fixtures/index.ts";
import {
stub,
assertSpyCalls,
type Stub,
assertSpyCall,
} from "@std/testing/mock";

describe("getAirtableData tests", () => {
const baseId = "app1234";
const tables = ["Items"];
const apiKey = "apikey1234";
const httpReadTimeout = 60;
let fetchStub: Stub;
beforeEach(() => {
fetchStub = stub(globalThis, "fetch", createFetchStubImplementation());
});

afterEach(() => {
fetchStub.restore();
});

it("should return a map of tables and records", async () => {
const airtableData = await getAirtableData(
baseId,
tables,
apiKey,
httpReadTimeout,
fetchStub as unknown as typeof fetch,
console,
);

assertEquals(airtableData.size, 1);
assertExists(airtableData.get("Items"));

const itemsData = airtableData.get("Items");
assertExists(itemsData);
assertEquals(itemsData.length, mockItemData.records.length);

assertEquals(itemsData[0], mockItemData.records[0]);
});

it("should handle pagination correctly", async () => {
const _airtableData = await getAirtableData(
baseId,
tables,
apiKey,
httpReadTimeout,
fetchStub as unknown as typeof fetch,
console,
);

assertSpyCalls(fetchStub, 2);
});
});
54 changes: 54 additions & 0 deletions tests/mocks/fetchStub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { itemData } from "../fixtures/index.ts";

type APIResponse = {
records: Record<string, unknown>[];
offset?: string;
};

const mockData: Map<string, APIResponse> = new Map([["Items_GET", itemData]]);

export function createFetchStubImplementation() {
return (
input: string | URL | Request,
init?: RequestInit,
): Promise<Response> => {
const url =
typeof input === "string"
? input
: input instanceof URL
? input.toString()
: input.url;

const parsedUrl = new URL(url);
const pathParts = parsedUrl.pathname.split("/");
const tableName = pathParts[pathParts.length - 1];
const offset = parsedUrl.searchParams.get("offset");
let key = `${tableName}_${init?.method || "GET"}`;
if (offset) {
key += `_${offset}`;
}

const responseData = mockData.get(key);

if (responseData) {
const offsetMatch = url.match(/offset=([^&]*)/);
const offset = offsetMatch ? offsetMatch[1] : undefined;

let response = { ...responseData };

if (offset && offset === response.offset) {
response = { records: [] };
}

return Promise.resolve(
new Response(JSON.stringify(response), { status: 200 }),
);
} else if (offset) {
// If there's an offset but no data, return an empty response to end the test loop
return Promise.resolve(
new Response(JSON.stringify({ records: [] }), { status: 200 }),
);
}
return Promise.resolve(new Response(null, { status: 500 }));
};
}

0 comments on commit bc4d84f

Please sign in to comment.