Skip to content

Commit

Permalink
fix(observable): improved waitfor test
Browse files Browse the repository at this point in the history
  • Loading branch information
bezoerb committed Apr 25, 2022
1 parent de01d56 commit e0ec526
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 20 deletions.
7 changes: 6 additions & 1 deletion packages/contentful-ssg/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,12 @@ export const run = async (config: Config): Promise<void> => {
await write({ ...transformContext, content }, ctx, config);
ctx.stats.addSuccess(transformContext);
} catch (error: unknown) {
subject.next({ ...transformContext, error });
if (error instanceof Error) {
subject.next({ ...transformContext, error });
} else if (typeof error === 'string') {
subject.next({ ...transformContext, error: new Error(error) });
}

if (error instanceof ValidationError) {
ctx.stats.addSkipped(transformContext, error);
} else if (typeof error === 'string' || error instanceof Error) {
Expand Down
37 changes: 26 additions & 11 deletions packages/contentful-ssg/src/lib/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,34 +190,49 @@ describe('Utils', () => {
const subject = new BehaviorSubject<TransformContext>(null);
const observable = subject.asObservable();

// let 9 finish regularly
setTimeout(() => {
subject.next({
...transformContext,
entry: entryMap.get('9'),
observable,
});
}, 100);

// mimic behaviour in index.ts
const waitMock = async (source: string, dest: string) => {
const waitMock = async (source: string, dest: string, delay: number) => {
await new Promise((resolve) => setTimeout(resolve, delay));
try {
await waitFor({ ...transformContext, entry: entryMap.get(source), observable })(dest, 1000);
subject.next({
...transformContext,
entry: entryMap.get(source),
observable,
});
return `SUCCESS ${source}`;
} catch (error) {
subject.next({
...transformContext,
entry: entryMap.get(source),
error,
observable,
});

throw error;
return `${error.message}`;
}
};

await expect(async () => {
await Promise.all([
waitMock('2', '4'),
waitMock('4', '1'),
waitMock('1', '3'),
waitMock('3', '2'),
]);
}).rejects.toThrowError(/Found cyclic dependency/);
const result = await Promise.all([
waitMock('6', '8', 0),
waitMock('8', '5', 10),
waitMock('5', '7', 20),
waitMock('7', '6', 30),
waitMock('3', '9', 40),
]);

expect(result[0]).toMatch('Found cyclic dependency in 6 (test-type): 6 -> 8 -> 5 -> 7 -> 6');
expect(result[1]).toMatch('Found cyclic dependency in 8 (test-type): 8 -> 5 -> 7 -> 6 -> 8');
expect(result[2]).toMatch('Found cyclic dependency in 5 (test-type): 5 -> 7 -> 6 -> 8 -> 5');
expect(result[3]).toMatch(/Awaited entry 6 \(test-type\) errored/);
expect(result[4]).toMatch('SUCCESS 3');
});
});
17 changes: 10 additions & 7 deletions packages/contentful-ssg/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const waitFor = (
const sourceEntry = transformContext.entry;
const sourceId = getContentId(sourceEntry);
const sourceContentTypeId = getContentTypeId(sourceEntry);
const source = `${sourceId} (${sourceContentTypeId})`;

return async (id: string, waitTimeout = DEFAULT_WAIT_TIMEOUT) => {
// Make sure we don't try to wait for the current entry
Expand All @@ -108,14 +109,14 @@ Entry ${source} waiting for ${source}.`);
}

waitForSubject.next({ source: getContentId(sourceEntry), dest: id });
const destEntry = transformContext.entryMap.get(id);
const destId = getContentId(destEntry);
const destContentTypeId = getContentTypeId(destEntry);
const dest = `${destId} (${destContentTypeId})`;

return new Promise((resolve, reject) => {
// If anything goes wrong, reject promise after waitTimeout
const timeout = setTimeout(() => {
const destEntry = transformContext.entryMap.get(id);
const source = `${sourceId} (${sourceContentTypeId})`;
const dest = `${getContentId(destEntry)} (${getContentTypeId(destEntry)})`;

reject(
new Error(
`Exceeded timeout of ${waitTimeout} ms while waiting for entry ${id} to complete.
Expand All @@ -130,19 +131,21 @@ Entry ${source} waiting for ${dest}.`
.subscribe((value) => {
clearTimeout(timeout);
if (value.error) {
reject(value.error);
reject(new Error(`Awaited entry ${dest} errored: ${value?.error?.message ?? ''}`));
} else {
resolve(value);
}
});

cyclicErrorObservable
.pipe(filter((v) => v?.[sourceId]?.some((value) => value.includes(sourceId))))
.pipe(filter((v) => v?.[sourceId]?.includes(sourceId)))
.pipe(distinct())
.subscribe((v) => {
clearTimeout(timeout);
const deps = v?.[sourceId] ?? [];
reject(new Error(`Found cyclic dependency: ${[sourceId, ...deps].join(' -> ')}`));
reject(
new Error(`Found cyclic dependency in ${source}: ${[sourceId, ...deps].join(' -> ')}`)
);
});
} else {
clearTimeout(timeout);
Expand Down
2 changes: 1 addition & 1 deletion packages/contentful-ssg/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export type TransformContext = LocalizedContent & {

export type ObservableContext = Readonly<
Pick<TransformContext, 'id' | 'contentTypeId' | 'entry' | 'content' | 'locale'> & {
error?: unknown;
error?: Error;
}
>;
export interface Ignore {
Expand Down

0 comments on commit e0ec526

Please sign in to comment.