diff --git a/packages/cli/project.json b/packages/cli/project.json index 2ec9c58bfdc..6f916188d3c 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -37,14 +37,14 @@ "lint": { "executor": "nx:run-commands", "options": { - "command": "pnpm eslint \"src/**/*.ts\" 'bin/*.js' ", + "command": "pnpm eslint src bin", "cwd": "packages/cli" } }, "lint:fix": { "executor": "nx:run-commands", "options": { - "command": "pnpm eslint 'src/**/*.ts' 'bin/*.js' --fix", + "command": "pnpm eslint src bin --fix", "cwd": "packages/cli" } }, diff --git a/packages/cli/src/cli/commands/docs/generate.ts b/packages/cli/src/cli/commands/docs/generate.ts index 2c5e90d8b2b..4c6c0859d25 100644 --- a/packages/cli/src/cli/commands/docs/generate.ts +++ b/packages/cli/src/cli/commands/docs/generate.ts @@ -90,7 +90,6 @@ export async function writeCommandDocumentation( const previewDescription = command.summary ?? description ?? '' const cleanPreview = previewDescription.replace(/`/g, '\\`').replace(/https:\/\/shopify\.dev/g, '') - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const category = hasTopic && !generalTopics.includes(topic!) ? topic : 'general commands' const docString = `// This is an autogenerated file. Don't edit this file manually. @@ -139,7 +138,7 @@ export async function writeCommandFlagInterface( const flag = command.flags[flagName] if (!flag) return if (flag.hidden) return - const flagDescription = flag.description || '' + const flagDescription = flag.description ?? '' const char = flag.char ? `-${flag.char}, ` : '' const type = flag.type === 'option' ? 'string' : "''" const value = flag.type === 'option' ? ' ' : '' diff --git a/packages/cli/src/cli/commands/store/auth.test.ts b/packages/cli/src/cli/commands/store/auth.test.ts index d2bc2c9a33d..d7e3a7d3c5b 100644 --- a/packages/cli/src/cli/commands/store/auth.test.ts +++ b/packages/cli/src/cli/commands/store/auth.test.ts @@ -1,14 +1,10 @@ -import {describe, test, expect, vi, beforeEach} from 'vitest' import StoreAuth from './auth.js' import {authenticateStoreWithApp} from '../../services/store/auth.js' +import {describe, test, expect, vi} from 'vitest' vi.mock('../../services/store/auth.js') describe('store auth command', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - test('passes parsed flags through to the auth service', async () => { await StoreAuth.run(['--store', 'shop.myshopify.com', '--scopes', 'read_products,write_products']) diff --git a/packages/cli/src/cli/commands/store/auth.ts b/packages/cli/src/cli/commands/store/auth.ts index 1fe48e3f3dc..64627852a29 100644 --- a/packages/cli/src/cli/commands/store/auth.ts +++ b/packages/cli/src/cli/commands/store/auth.ts @@ -1,8 +1,8 @@ +import {authenticateStoreWithApp} from '../../services/store/auth.js' import Command from '@shopify/cli-kit/node/base-command' import {globalFlags} from '@shopify/cli-kit/node/cli' import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn' import {Flags} from '@oclif/core' -import {authenticateStoreWithApp} from '../../services/store/auth.js' export default class StoreAuth extends Command { static summary = 'Authenticate an app against a store for store commands.' @@ -13,7 +13,9 @@ Re-run this command if the stored token is missing, expires, or no longer has th static description = this.descriptionWithoutMarkdown() - static examples = ['<%= config.bin %> <%= command.id %> --store shop.myshopify.com --scopes read_products,write_products'] + static examples = [ + '<%= config.bin %> <%= command.id %> --store shop.myshopify.com --scopes read_products,write_products', + ] static flags = { ...globalFlags, diff --git a/packages/cli/src/cli/commands/store/execute.test.ts b/packages/cli/src/cli/commands/store/execute.test.ts index e890b5332a0..3c8c34f4956 100644 --- a/packages/cli/src/cli/commands/store/execute.test.ts +++ b/packages/cli/src/cli/commands/store/execute.test.ts @@ -1,14 +1,10 @@ -import {describe, test, expect, vi, beforeEach} from 'vitest' import StoreExecute from './execute.js' import {executeStoreOperation} from '../../services/store/execute.js' +import {describe, test, expect, vi} from 'vitest' vi.mock('../../services/store/execute.js') describe('store execute command', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - test('passes the inline query through to the service', async () => { await StoreExecute.run(['--store', 'shop.myshopify.com', '--query', 'query { shop { name } }']) diff --git a/packages/cli/src/cli/commands/store/execute.ts b/packages/cli/src/cli/commands/store/execute.ts index 661c8af9a24..5d2653faf2f 100644 --- a/packages/cli/src/cli/commands/store/execute.ts +++ b/packages/cli/src/cli/commands/store/execute.ts @@ -1,9 +1,9 @@ +import {executeStoreOperation} from '../../services/store/execute.js' import Command from '@shopify/cli-kit/node/base-command' import {globalFlags} from '@shopify/cli-kit/node/cli' import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn' import {resolvePath} from '@shopify/cli-kit/node/path' import {Flags} from '@oclif/core' -import {executeStoreOperation} from '../../services/store/execute.js' export default class StoreExecute extends Command { static summary = 'Execute GraphQL queries and mutations on a store.' diff --git a/packages/cli/src/cli/services/kitchen-sink/static.ts b/packages/cli/src/cli/services/kitchen-sink/static.ts index 32a01e8c1e6..9aee696cd37 100644 --- a/packages/cli/src/cli/services/kitchen-sink/static.ts +++ b/packages/cli/src/cli/services/kitchen-sink/static.ts @@ -35,7 +35,7 @@ export async function staticService() { }) renderInfo({ - headline: 'About your app', + headline: 'About your app.', customSections: [ { body: { diff --git a/packages/cli/src/cli/services/store/admin-graphql-context.test.ts b/packages/cli/src/cli/services/store/admin-graphql-context.test.ts index 137c3f2761f..29561a6a850 100644 --- a/packages/cli/src/cli/services/store/admin-graphql-context.test.ts +++ b/packages/cli/src/cli/services/store/admin-graphql-context.test.ts @@ -1,7 +1,3 @@ -import {beforeEach, describe, expect, test, vi} from 'vitest' -import {fetchApiVersions} from '@shopify/cli-kit/node/api/admin' -import {AbortError} from '@shopify/cli-kit/node/error' -import {fetch} from '@shopify/cli-kit/node/http' import { clearStoredStoreAppSession, getStoredStoreAppSession, @@ -10,11 +6,17 @@ import { } from './session.js' import {STORE_AUTH_APP_CLIENT_ID} from './auth-config.js' import {prepareAdminStoreGraphQLContext} from './admin-graphql-context.js' +import {beforeEach, describe, expect, test, vi} from 'vitest' +import {fetchApiVersions} from '@shopify/cli-kit/node/api/admin' +import {AbortError} from '@shopify/cli-kit/node/error' +import {fetch} from '@shopify/cli-kit/node/http' vi.mock('./session.js') vi.mock('@shopify/cli-kit/node/http') vi.mock('@shopify/cli-kit/node/api/admin', async () => { - const actual = await vi.importActual('@shopify/cli-kit/node/api/admin') + const actual = await vi.importActual( + '@shopify/cli-kit/node/api/admin', + ) return { ...actual, fetchApiVersions: vi.fn(), @@ -35,7 +37,6 @@ describe('prepareAdminStoreGraphQLContext', () => { } beforeEach(() => { - vi.clearAllMocks() vi.mocked(getStoredStoreAppSession).mockReturnValue(storedSession) vi.mocked(isSessionExpired).mockReturnValue(false) vi.mocked(fetchApiVersions).mockResolvedValue([ diff --git a/packages/cli/src/cli/services/store/admin-graphql-context.ts b/packages/cli/src/cli/services/store/admin-graphql-context.ts index f014e5b9e9e..1d06f3d1a43 100644 --- a/packages/cli/src/cli/services/store/admin-graphql-context.ts +++ b/packages/cli/src/cli/services/store/admin-graphql-context.ts @@ -1,8 +1,3 @@ -import {fetchApiVersions} from '@shopify/cli-kit/node/api/admin' -import {AbortError} from '@shopify/cli-kit/node/error' -import {fetch} from '@shopify/cli-kit/node/http' -import {outputContent, outputDebug, outputToken} from '@shopify/cli-kit/node/output' -import {AdminSession} from '@shopify/cli-kit/node/session' import {maskToken, STORE_AUTH_APP_CLIENT_ID} from './auth-config.js' import {createStoredStoreAuthError, reauthenticateStoreAuthError} from './auth-recovery.js' import { @@ -12,6 +7,11 @@ import { setStoredStoreAppSession, StoredStoreAppSession, } from './session.js' +import {fetchApiVersions} from '@shopify/cli-kit/node/api/admin' +import {AbortError} from '@shopify/cli-kit/node/error' +import {fetch} from '@shopify/cli-kit/node/http' +import {outputContent, outputDebug, outputToken} from '@shopify/cli-kit/node/output' +import {AdminSession} from '@shopify/cli-kit/node/session' export interface AdminStoreGraphQLContext { adminSession: AdminSession diff --git a/packages/cli/src/cli/services/store/admin-graphql-transport.test.ts b/packages/cli/src/cli/services/store/admin-graphql-transport.test.ts index a0d03fc1051..c791b1ca1b3 100644 --- a/packages/cli/src/cli/services/store/admin-graphql-transport.test.ts +++ b/packages/cli/src/cli/services/store/admin-graphql-transport.test.ts @@ -1,16 +1,18 @@ +import {clearStoredStoreAppSession} from './session.js' +import {prepareStoreExecuteRequest} from './execute-request.js' +import {runAdminStoreGraphQLOperation} from './admin-graphql-transport.js' import {beforeEach, describe, expect, test, vi} from 'vitest' import {adminUrl} from '@shopify/cli-kit/node/api/admin' import {graphqlRequest} from '@shopify/cli-kit/node/api/graphql' import {renderSingleTask} from '@shopify/cli-kit/node/ui' -import {clearStoredStoreAppSession} from './session.js' -import {prepareStoreExecuteRequest} from './execute-request.js' -import {runAdminStoreGraphQLOperation} from './admin-graphql-transport.js' vi.mock('./session.js') vi.mock('@shopify/cli-kit/node/api/graphql') vi.mock('@shopify/cli-kit/node/ui') vi.mock('@shopify/cli-kit/node/api/admin', async () => { - const actual = await vi.importActual('@shopify/cli-kit/node/api/admin') + const actual = await vi.importActual( + '@shopify/cli-kit/node/api/admin', + ) return { ...actual, adminUrl: vi.fn(), @@ -22,7 +24,6 @@ describe('runAdminStoreGraphQLOperation', () => { const adminSession = {token: 'token', storeFqdn: store} beforeEach(() => { - vi.clearAllMocks() vi.mocked(adminUrl).mockReturnValue('https://shop.myshopify.com/admin/api/2025-10/graphql.json') vi.mocked(renderSingleTask).mockImplementation(async ({task}) => task(() => {})) }) diff --git a/packages/cli/src/cli/services/store/admin-graphql-transport.ts b/packages/cli/src/cli/services/store/admin-graphql-transport.ts index 1a104ee160e..bf138a61023 100644 --- a/packages/cli/src/cli/services/store/admin-graphql-transport.ts +++ b/packages/cli/src/cli/services/store/admin-graphql-transport.ts @@ -1,17 +1,17 @@ +import {clearStoredStoreAppSession} from './session.js' +import {PreparedStoreExecuteRequest} from './execute-request.js' +import {reauthenticateStoreAuthError} from './auth-recovery.js' import {adminUrl} from '@shopify/cli-kit/node/api/admin' import {graphqlRequest} from '@shopify/cli-kit/node/api/graphql' import {AbortError} from '@shopify/cli-kit/node/error' import {outputContent} from '@shopify/cli-kit/node/output' import {AdminSession} from '@shopify/cli-kit/node/session' import {renderSingleTask} from '@shopify/cli-kit/node/ui' -import {reauthenticateStoreAuthError} from './auth-recovery.js' -import {PreparedStoreExecuteRequest} from './execute-request.js' -import {clearStoredStoreAppSession} from './session.js' function isGraphQLClientError(error: unknown): error is {response: {errors?: unknown; status?: number}} { if (!error || typeof error !== 'object' || !('response' in error)) return false const response = (error as {response?: unknown}).response - return !!response && typeof response === 'object' + return Boolean(response) && typeof response === 'object' } export async function runAdminStoreGraphQLOperation(input: { diff --git a/packages/cli/src/cli/services/store/auth.test.ts b/packages/cli/src/cli/services/store/auth.test.ts index 0ae4fe7c94e..8bd6a17d0a1 100644 --- a/packages/cli/src/cli/services/store/auth.test.ts +++ b/packages/cli/src/cli/services/store/auth.test.ts @@ -1,5 +1,3 @@ -import {createServer} from 'http' -import {describe, test, expect, vi, beforeEach, afterEach} from 'vitest' import { authenticateStoreWithApp, buildStoreAuthUrl, @@ -11,7 +9,9 @@ import { } from './auth.js' import {setStoredStoreAppSession} from './session.js' import {STORE_AUTH_APP_CLIENT_ID} from './auth-config.js' +import {describe, test, expect, vi} from 'vitest' import {fetch} from '@shopify/cli-kit/node/http' +import {createServer} from 'http' vi.mock('./session.js') vi.mock('@shopify/cli-kit/node/http') @@ -19,7 +19,7 @@ vi.mock('@shopify/cli-kit/node/system', () => ({openURL: vi.fn().mockResolvedVal vi.mock('@shopify/cli-kit/node/crypto', () => ({randomUUID: vi.fn().mockReturnValue('state-123')})) async function getAvailablePort(): Promise { - return await new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const server = createServer() server.on('error', reject) @@ -42,12 +42,7 @@ async function getAvailablePort(): Promise { }) } -function callbackParams(options?: { - code?: string - shop?: string - state?: string - error?: string -}): URLSearchParams { +function callbackParams(options?: {code?: string; shop?: string; state?: string; error?: string}): URLSearchParams { const params = new URLSearchParams() params.set('shop', options?.shop ?? 'shop.myshopify.com') params.set('state', options?.state ?? 'state-123') @@ -60,23 +55,15 @@ function callbackParams(options?: { } describe('store auth service', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - - afterEach(() => { - vi.restoreAllMocks() - }) - test('generateCodeVerifier produces a base64url string of 43 chars', () => { const verifier = generateCodeVerifier() expect(verifier).toMatch(/^[A-Za-z0-9_-]{43}$/) }) test('generateCodeVerifier produces unique values', () => { - const a = generateCodeVerifier() - const b = generateCodeVerifier() - expect(a).not.toBe(b) + const firstVerifier = generateCodeVerifier() + const secondVerifier = generateCodeVerifier() + expect(firstVerifier).not.toBe(secondVerifier) }) test('computeCodeChallenge produces a deterministic S256 hash', () => { diff --git a/packages/cli/src/cli/services/store/auth.ts b/packages/cli/src/cli/services/store/auth.ts index 0b38fc842d3..30aa08c3b60 100644 --- a/packages/cli/src/cli/services/store/auth.ts +++ b/packages/cli/src/cli/services/store/auth.ts @@ -1,4 +1,10 @@ -import {DEFAULT_STORE_AUTH_PORT, STORE_AUTH_APP_CLIENT_ID, STORE_AUTH_CALLBACK_PATH, maskToken, storeAuthRedirectUri} from './auth-config.js' +import { + DEFAULT_STORE_AUTH_PORT, + STORE_AUTH_APP_CLIENT_ID, + STORE_AUTH_CALLBACK_PATH, + maskToken, + storeAuthRedirectUri, +} from './auth-config.js' import {retryStoreAuthWithPermanentDomainError} from './auth-recovery.js' import {setStoredStoreAppSession} from './session.js' import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn' @@ -138,16 +144,8 @@ export function buildStoreAuthUrl(options: { } function renderAuthCallbackPage(title: string, message: string): string { - const safeTitle = title - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - const safeMessage = message - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') + const safeTitle = title.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"') + const safeMessage = message.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"') return ` @@ -243,7 +241,9 @@ export async function waitForStoreAuthCode({ res.setHeader('Content-Type', 'text/html') res.setHeader('Connection', 'close') res.once('finish', () => settle(() => resolve(code))) - res.end(renderAuthCallbackPage('Authentication succeeded', 'You can close this window and return to the terminal.')) + res.end( + renderAuthCallbackPage('Authentication succeeded', 'You can close this window and return to the terminal.'), + ) }) const settle = (callback: () => void) => { @@ -285,7 +285,7 @@ export async function waitForStoreAuthCode({ settleWithError(error) }) - server.listen(port, '127.0.0.1', async () => { + server.listen(port, '127.0.0.1', () => { isListening = true outputDebug( outputContent`PKCE callback server listening on http://127.0.0.1:${outputToken.raw(String(port))}${outputToken.raw(STORE_AUTH_CALLBACK_PATH)}`, @@ -293,18 +293,16 @@ export async function waitForStoreAuthCode({ if (!onListening) return - try { - await onListening() - } catch (error) { + onListening()?.catch((error: unknown) => { settleWithError(error instanceof Error ? error : new Error(String(error))) - } + }) }) }) } -function constantTimeEqual(a: string, b: string): boolean { - if (a.length !== b.length) return false - return timingSafeEqual(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8')) +function constantTimeEqual(first: string, second: string): boolean { + if (first.length !== second.length) return false + return timingSafeEqual(Buffer.from(first, 'utf8'), Buffer.from(second, 'utf8')) } export async function exchangeStoreAuthCodeForToken(options: { @@ -329,28 +327,28 @@ export async function exchangeStoreAuthCodeForToken(options: { }) const body = await response.text() - if (!response.ok) { + if (response.ok) { + let parsed: StoreTokenResponse + try { + parsed = JSON.parse(body) as StoreTokenResponse + } catch { + throw new AbortError('Received an invalid token response from Shopify.') + } + outputDebug( - outputContent`Token exchange failed with HTTP ${outputToken.raw(String(response.status))}: ${outputToken.raw(body.slice(0, 300))}`, + outputContent`Token exchange succeeded: access_token=${outputToken.raw(maskToken(parsed.access_token))}, refresh_token=${outputToken.raw(parsed.refresh_token ? maskToken(parsed.refresh_token) : 'none')}, expires_in=${outputToken.raw(String(parsed.expires_in ?? 'unknown'))}s, user=${outputToken.raw(String(parsed.associated_user?.id ?? 'unknown'))} (${outputToken.raw(parsed.associated_user?.email ?? 'no email')})`, ) - throw new AbortError( - `Failed to exchange OAuth code for an access token (HTTP ${response.status}).`, - body || response.statusText, - ) - } - let parsed: StoreTokenResponse - try { - parsed = JSON.parse(body) as StoreTokenResponse - } catch { - throw new AbortError('Received an invalid token response from Shopify.') + return parsed } outputDebug( - outputContent`Token exchange succeeded: access_token=${outputToken.raw(maskToken(parsed.access_token))}, refresh_token=${outputToken.raw(parsed.refresh_token ? maskToken(parsed.refresh_token) : 'none')}, expires_in=${outputToken.raw(String(parsed.expires_in ?? 'unknown'))}s, user=${outputToken.raw(String(parsed.associated_user?.id ?? 'unknown'))} (${outputToken.raw(parsed.associated_user?.email ?? 'no email')})`, + outputContent`Token exchange failed with HTTP ${outputToken.raw(String(response.status))}: ${outputToken.raw(body.slice(0, 300))}`, + ) + throw new AbortError( + `Failed to exchange OAuth code for an access token (HTTP ${response.status}).`, + body === '' ? response.statusText : body, ) - - return parsed } interface StoreAuthPresenter { @@ -436,7 +434,7 @@ export async function authenticateStoreWithApp( ): Promise { const bootstrap = createPkceBootstrap(input, dependencies.exchangeStoreAuthCodeForToken) const { - authorization: {store, scopes, redirectUri, authorizationUrl}, + authorization: {store, scopes, authorizationUrl}, } = bootstrap dependencies.presenter.openingBrowser() diff --git a/packages/cli/src/cli/services/store/execute-request.test.ts b/packages/cli/src/cli/services/store/execute-request.test.ts index 7146746bced..2cf47459bc7 100644 --- a/packages/cli/src/cli/services/store/execute-request.test.ts +++ b/packages/cli/src/cli/services/store/execute-request.test.ts @@ -1,14 +1,10 @@ -import {beforeEach, describe, expect, test, vi} from 'vitest' -import {fileExists, readFile} from '@shopify/cli-kit/node/fs' import {prepareStoreExecuteRequest} from './execute-request.js' +import {describe, expect, test, vi} from 'vitest' +import {fileExists, readFile} from '@shopify/cli-kit/node/fs' vi.mock('@shopify/cli-kit/node/fs') describe('prepareStoreExecuteRequest', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - test('returns a prepared request for an inline query', async () => { const request = await prepareStoreExecuteRequest({ query: 'query { shop { name } }', diff --git a/packages/cli/src/cli/services/store/execute-request.ts b/packages/cli/src/cli/services/store/execute-request.ts index 7524b74b87d..17d73934a6b 100644 --- a/packages/cli/src/cli/services/store/execute-request.ts +++ b/packages/cli/src/cli/services/store/execute-request.ts @@ -149,4 +149,3 @@ export async function prepareStoreExecuteRequest(input: { requestedVersion: input.version, } } - diff --git a/packages/cli/src/cli/services/store/execute-result.test.ts b/packages/cli/src/cli/services/store/execute-result.test.ts index 2a370560acf..bf4627726cf 100644 --- a/packages/cli/src/cli/services/store/execute-result.test.ts +++ b/packages/cli/src/cli/services/store/execute-result.test.ts @@ -1,15 +1,14 @@ +import {writeOrOutputStoreExecuteResult} from './execute-result.js' import {beforeEach, describe, expect, test, vi} from 'vitest' import {writeFile} from '@shopify/cli-kit/node/fs' import {renderSuccess} from '@shopify/cli-kit/node/ui' import {mockAndCaptureOutput} from '@shopify/cli-kit/node/testing/output' -import {writeOrOutputStoreExecuteResult} from './execute-result.js' vi.mock('@shopify/cli-kit/node/fs') vi.mock('@shopify/cli-kit/node/ui') describe('writeOrOutputStoreExecuteResult', () => { beforeEach(() => { - vi.clearAllMocks() mockAndCaptureOutput().clear() }) diff --git a/packages/cli/src/cli/services/store/execute.test.ts b/packages/cli/src/cli/services/store/execute.test.ts index e9ab1276937..4053a08bd1b 100644 --- a/packages/cli/src/cli/services/store/execute.test.ts +++ b/packages/cli/src/cli/services/store/execute.test.ts @@ -1,7 +1,7 @@ -import {describe, test, expect, vi, beforeEach, afterEach} from 'vitest' import {executeStoreOperation} from './execute.js' import {getStoredStoreAppSession} from './session.js' import {STORE_AUTH_APP_CLIENT_ID} from './auth-config.js' +import {describe, test, expect, vi, beforeEach, afterEach} from 'vitest' import {fetchApiVersions, adminUrl} from '@shopify/cli-kit/node/api/admin' import {graphqlRequest} from '@shopify/cli-kit/node/api/graphql' import {renderSingleTask, renderSuccess} from '@shopify/cli-kit/node/ui' @@ -13,7 +13,9 @@ vi.mock('@shopify/cli-kit/node/api/graphql') vi.mock('@shopify/cli-kit/node/ui') vi.mock('@shopify/cli-kit/node/fs') vi.mock('@shopify/cli-kit/node/api/admin', async () => { - const actual = await vi.importActual('@shopify/cli-kit/node/api/admin') + const actual = await vi.importActual( + '@shopify/cli-kit/node/api/admin', + ) return { ...actual, fetchApiVersions: vi.fn(), @@ -34,7 +36,6 @@ describe('executeStoreOperation', () => { } beforeEach(() => { - vi.clearAllMocks() vi.mocked(getStoredStoreAppSession).mockReturnValue(storedSession) vi.mocked(fetchApiVersions).mockResolvedValue([ {handle: '2025-10', supported: true}, @@ -215,5 +216,4 @@ describe('executeStoreOperation', () => { }), ).rejects.toThrow('GraphQL operation failed.') }) - }) diff --git a/packages/cli/src/cli/services/store/execute.ts b/packages/cli/src/cli/services/store/execute.ts index 899bf5a662d..8cde3d4047c 100644 --- a/packages/cli/src/cli/services/store/execute.ts +++ b/packages/cli/src/cli/services/store/execute.ts @@ -1,8 +1,8 @@ -import {renderSingleTask} from '@shopify/cli-kit/node/ui' -import {outputContent} from '@shopify/cli-kit/node/output' import {prepareStoreExecuteRequest} from './execute-request.js' import {writeOrOutputStoreExecuteResult} from './execute-result.js' import {getStoreGraphQLTarget, StoreGraphQLApi} from './graphql-targets.js' +import {outputContent} from '@shopify/cli-kit/node/output' +import {renderSingleTask} from '@shopify/cli-kit/node/ui' interface ExecuteStoreOperationInput { store: string diff --git a/packages/cli/src/cli/services/store/graphql-targets.test.ts b/packages/cli/src/cli/services/store/graphql-targets.test.ts index a5fba30398d..9d08b50fba3 100644 --- a/packages/cli/src/cli/services/store/graphql-targets.test.ts +++ b/packages/cli/src/cli/services/store/graphql-targets.test.ts @@ -1,17 +1,13 @@ -import {beforeEach, describe, expect, test, vi} from 'vitest' import {prepareStoreExecuteRequest} from './execute-request.js' import {prepareAdminStoreGraphQLContext} from './admin-graphql-context.js' import {runAdminStoreGraphQLOperation} from './admin-graphql-transport.js' import {getStoreGraphQLTarget} from './graphql-targets.js' +import {describe, expect, test, vi} from 'vitest' vi.mock('./admin-graphql-context.js') vi.mock('./admin-graphql-transport.js') describe('getStoreGraphQLTarget', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - test('returns the admin target adapter', async () => { const target = getStoreGraphQLTarget('admin') const request = await prepareStoreExecuteRequest({query: 'query { shop { name } }'}) @@ -24,7 +20,9 @@ describe('getStoreGraphQLTarget', () => { vi.mocked(prepareAdminStoreGraphQLContext).mockResolvedValue(context) vi.mocked(runAdminStoreGraphQLOperation).mockResolvedValue({data: {shop: {name: 'Test shop'}}}) - await expect(target.prepareContext({store: 'shop.myshopify.com', requestedVersion: '2025-10'})).resolves.toEqual(context) + await expect(target.prepareContext({store: 'shop.myshopify.com', requestedVersion: '2025-10'})).resolves.toEqual( + context, + ) await expect(target.execute({store: 'shop.myshopify.com', context, request})).resolves.toEqual({ data: {shop: {name: 'Test shop'}}, diff --git a/packages/cli/src/cli/services/store/graphql-targets.ts b/packages/cli/src/cli/services/store/graphql-targets.ts index 809568d7e2e..9b4e0b66cde 100644 --- a/packages/cli/src/cli/services/store/graphql-targets.ts +++ b/packages/cli/src/cli/services/store/graphql-targets.ts @@ -1,7 +1,7 @@ -import {BugError} from '@shopify/cli-kit/node/error' import {PreparedStoreExecuteRequest} from './execute-request.js' import {prepareAdminStoreGraphQLContext, AdminStoreGraphQLContext} from './admin-graphql-context.js' import {runAdminStoreGraphQLOperation} from './admin-graphql-transport.js' +import {BugError} from '@shopify/cli-kit/node/error' export type StoreGraphQLApi = 'admin' diff --git a/packages/cli/src/cli/services/store/session.test.ts b/packages/cli/src/cli/services/store/session.test.ts index 373fb0d4286..102476d580a 100644 --- a/packages/cli/src/cli/services/store/session.test.ts +++ b/packages/cli/src/cli/services/store/session.test.ts @@ -1,5 +1,3 @@ -import {describe, test, expect} from 'vitest' -import {LocalStorage} from '@shopify/cli-kit/node/local-storage' import {STORE_AUTH_APP_CLIENT_ID, storeAuthSessionKey} from './auth-config.js' import { clearStoredStoreAppSession, @@ -8,6 +6,8 @@ import { isSessionExpired, type StoredStoreAppSession, } from './session.js' +import {describe, test, expect} from 'vitest' +import {LocalStorage} from '@shopify/cli-kit/node/local-storage' function inMemoryStorage() { const values = new Map() diff --git a/packages/cli/src/cli/services/store/session.ts b/packages/cli/src/cli/services/store/session.ts index 53100a27e87..d987f443a0b 100644 --- a/packages/cli/src/cli/services/store/session.ts +++ b/packages/cli/src/cli/services/store/session.ts @@ -1,5 +1,5 @@ -import {LocalStorage} from '@shopify/cli-kit/node/local-storage' import {storeAuthSessionKey} from './auth-config.js' +import {LocalStorage} from '@shopify/cli-kit/node/local-storage' export interface StoredStoreAppSession { store: string @@ -85,8 +85,7 @@ export function clearStoredStoreAppSession( maybeStorage?: LocalStorage, ): void { const userId = typeof userIdOrStorage === 'string' ? userIdOrStorage : undefined - const storage = - (typeof userIdOrStorage === 'string' ? maybeStorage : userIdOrStorage) ?? storeSessionStorage() + const storage = (typeof userIdOrStorage === 'string' ? maybeStorage : userIdOrStorage) ?? storeSessionStorage() const key = storeAuthSessionKey(store) @@ -107,8 +106,7 @@ export function clearStoredStoreAppSession( } storage.set(key, { - currentUserId: - existingBucket.currentUserId === userId ? remainingUserIds[0]! : existingBucket.currentUserId, + currentUserId: existingBucket.currentUserId === userId ? remainingUserIds[0]! : existingBucket.currentUserId, sessionsByUserId: remainingSessions, }) }