Repository navigation
[Tests] Cover abortSignalFromRequestBehaviour request cancellation - #8696
Merged
Merged
Conversation
`abortSignalFromRequestBehaviour` decides whether an HTTP request can be cancelled, and is used by both shopifyFetch and the GraphQL client, but had no direct tests: its sibling `requestMode` was covered while all three of its branches were only exercised indirectly through shopifyFetch. Cover the timeout, disabled, factory-function and supplied-signal cases, and assert that each call returns a fresh signal so a retried request is not born aborted. `AbortSignal.timeout` is backed by libuv rather than a JS timer, so the timeout cases use real timers and await the abort event instead of sleeping on a fixed delay. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 of 4 tasks
Suleimanlatrsh
marked this pull request as ready for review
September 29, 2026 16:22
Suleimanlatrsh
approved these changes
Sep 29, 2026
Contributor
Author
Differences in type declarationsWe detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:
New type declarationsWe found no new type declarations in this PR Existing type declarationspackages/cli-kit/dist/public/common/command-events.d.ts@@ -23,14 +23,14 @@ export declare const commandDiagnosticEventSchema: z.ZodObject<{
export declare const commandProgressEventSchema: z.ZodObject<{
type: z.ZodLiteral<"progress">;
timestamp: z.ZodString;
- status: z.ZodEnum<["started", "updated", "retrying", "completed", "failed"]>;
+ status: z.ZodEnum<["started", "updated", "completed"]>;
operation: z.ZodString;
message: z.ZodOptional<z.ZodString>;
current: z.ZodOptional<z.ZodNumber>;
total: z.ZodOptional<z.ZodNumber>;
}, "strict", z.ZodTypeAny, {
type: "progress";
- status: "started" | "updated" | "retrying" | "completed" | "failed";
+ status: "started" | "updated" | "completed";
timestamp: string;
operation: string;
message?: string | undefined;
@@ -38,7 +38,7 @@ export declare const commandProgressEventSchema: z.ZodObject<{
total?: number | undefined;
}, {
type: "progress";
- status: "started" | "updated" | "retrying" | "completed" | "failed";
+ status: "started" | "updated" | "completed";
timestamp: string;
operation: string;
message?: string | undefined;
@@ -67,14 +67,14 @@ export declare const commandEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
}>, z.ZodObject<{
type: z.ZodLiteral<"progress">;
timestamp: z.ZodString;
- status: z.ZodEnum<["started", "updated", "retrying", "completed", "failed"]>;
+ status: z.ZodEnum<["started", "updated", "completed"]>;
operation: z.ZodString;
message: z.ZodOptional<z.ZodString>;
current: z.ZodOptional<z.ZodNumber>;
total: z.ZodOptional<z.ZodNumber>;
}, "strict", z.ZodTypeAny, {
type: "progress";
- status: "started" | "updated" | "retrying" | "completed" | "failed";
+ status: "started" | "updated" | "completed";
timestamp: string;
operation: string;
message?: string | undefined;
@@ -82,7 +82,7 @@ export declare const commandEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
total?: number | undefined;
}, {
type: "progress";
- status: "started" | "updated" | "retrying" | "completed" | "failed";
+ status: "started" | "updated" | "completed";
timestamp: string;
operation: string;
message?: string | undefined;
packages/cli-kit/dist/public/node/command-events.d.ts@@ -29,14 +29,14 @@ export declare const commandEventOutputSchema: import("./json-output-schema.js")
}>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"progress">;
timestamp: import("zod").ZodString;
- status: import("zod").ZodEnum<["started", "updated", "retrying", "completed", "failed"]>;
+ status: import("zod").ZodEnum<["started", "updated", "completed"]>;
operation: import("zod").ZodString;
message: import("zod").ZodOptional<import("zod").ZodString>;
current: import("zod").ZodOptional<import("zod").ZodNumber>;
total: import("zod").ZodOptional<import("zod").ZodNumber>;
}, "strict", import("zod").ZodTypeAny, {
type: "progress";
- status: "started" | "updated" | "retrying" | "completed" | "failed";
+ status: "started" | "updated" | "completed";
timestamp: string;
operation: string;
message?: string | undefined;
@@ -44,7 +44,7 @@ export declare const commandEventOutputSchema: import("./json-output-schema.js")
total?: number | undefined;
}, {
type: "progress";
- status: "started" | "updated" | "retrying" | "completed" | "failed";
+ status: "started" | "updated" | "completed";
timestamp: string;
operation: string;
message?: string | undefined;
packages/cli-kit/dist/public/node/ui.d.ts@@ -318,8 +318,6 @@ export declare function renderTasks<TContext>(tasks: Task<TContext>[], { renderO
export interface RenderSingleTaskOptions<T> {
title: TokenizedString;
task: (updateStatus: (status: TokenizedString) => void) => Promise<T>;
- /** The number of additional attempts after a failure. Defaults to zero. */
- retry?: number;
onAbort?: () => void;
renderOptions?: RenderOptions;
}
@@ -328,13 +326,12 @@ export interface RenderSingleTaskOptions<T> {
* @param options - Configuration object
* @param options.title - The initial title to display with the loading bar
* @param options.task - The async task to execute. Receives an updateStatus callback to change the displayed title.
- * @param options.retry - The number of additional attempts after a failure. Defaults to zero.
* @param options.renderOptions - Optional render configuration
* @returns The result of the task
* @example
* Loading app ...
*/
-export declare function renderSingleTask<T>({ title, task, retry, onAbort, renderOptions, }: RenderSingleTaskOptions<T>): Promise<T>;
+export declare function renderSingleTask<T>({ title, task, onAbort, renderOptions, }: RenderSingleTaskOptions<T>): Promise<T>;
export interface RenderTextPromptOptions extends Omit<TextPromptProps, 'onSubmit'> {
renderOptions?: RenderOptions;
}
packages/cli-kit/dist/private/node/ui/hooks/use-async-and-unmount.d.ts@@ -1,6 +1,6 @@
-interface Options<T> {
- onFulfilled?: (result: T) => unknown;
+interface Options {
+ onFulfilled?: () => unknown;
onRejected?: (error: Error) => void;
}
-export default function useAsyncAndUnmount<T>(asyncFunction: () => Promise<T>, { onFulfilled, onRejected }?: Options<T>): void;
+export default function useAsyncAndUnmount(asyncFunction: () => Promise<unknown>, { onFulfilled, onRejected }?: Options): void;
export {};
\ No newline at end of file
packages/cli-kit/dist/private/node/ui/components/Tasks.d.ts@@ -1,7 +1,14 @@
import { AbortSignal } from '../../../../public/node/abort.js';
-import { Task } from '../tasks.js';
+import { TokenizedString } from '../../../../public/node/output.js';
import React from 'react';
-export type { Task } from '../tasks.js';
+export interface Task<TContext = unknown> {
+ title: string | TokenizedString;
+ task: (ctx: TContext, task: Task<TContext>) => Promise<void | Task<TContext>[]>;
+ retry?: number;
+ retryCount?: number;
+ errors?: Error[];
+ skip?: (ctx: TContext) => boolean;
+}
interface TasksProps<TContext> {
tasks: Task<TContext>[];
silent?: boolean;
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WHY are these changes introduced?
The seven-day review of Main tests runs (2026-09-22T00:00Z through 2026-09-29T00:27Z UTC) found 10 failed
mainruns, all from the same job —[Main] Node 22.12.0 in windows-latest— and all the same signature:version.test.tssubprocess assertions timing out at 20000ms (representative job). That flake is already addressed by open PR #8669, and the one stable/4.8 failure in the window was a real npm audit timeout already fixed onmainin 6b70f18. With no actionable, non-duplicate flake remaining, this PR closes a coverage gap instead.abortSignalFromRequestBehaviourinpackages/cli-kit/src/public/node/http.ts:108decides whether an HTTP request can be cancelled at all. It is used byshopifyFetchand by the GraphQL client (packages/cli-kit/src/public/node/api/graphql.ts:145), but had no direct tests: its siblingrequestModehas a fulldescribeblock, while all three of this function's branches were only exercised indirectly throughshopifyFetch, where an assertion failure reports as a fetch error rather than naming the faulty branch.WHAT is this pull request doing?
Adds a
describeblock to the existinghttp.test.tscovering the function's contract: the timeout case, the disabled case, a signal from a factory function, a signal supplied directly, and that each call returns a fresh signal — the property that keeps a retried request from starting out already aborted.AbortSignal.timeoutis backed by libuv rather than a JS timer, so the file's faked timers never fire it. The two timeout cases callvi.useRealTimers()(matching the existing pattern athttp.test.ts:122) and await theabortevent with a 10ms timeout instead of sleeping on a fixed delay, so they finish in ~11ms and do not depend on wall-clock slack.No production code changed.
Validation on Linux / Node 26.1.0:
http.test.tspass, as do 170 tests across the dependentapiandenvironmentsuites.--sequence.shuffle, varied seeds) and a--pool=forksrun all pass, so the new tests are not order- or worker-dependent.eslintandtsc --noEmitonpackages/cli-kitare clean.shopifyFetchcases).Windows and macOS are left to CI; the assertions are platform-independent, but only CI confirms the originally failing platform.
How to manually test your changes?
CI
Checklist
patchfor bug fixes ·minorfor new features ·majorfor breaking changes) and added a changeset withpnpm changeset add