Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import {
} from '../../models/app/app.test-data.js'
import {ExtensionInstance} from '../../models/extensions/extension-instance.js'
import {ListApps} from '../../api/graphql/app-management/generated/apps.js'
import {
FetchStoreByDomain,
FetchStoreByDomainQuery,
} from '../../api/graphql/business-platform-organizations/generated/fetch_store_by_domain.js'
import {
ListAppDevStores,
ListAppDevStoresQuery,
Expand Down Expand Up @@ -1452,6 +1456,133 @@ describe('AppManagementClient', () => {
})
})

describe('storeByDomain', () => {
test('queries Business Platform with STORE_STATUS=ACTIVE for each requested store type', async () => {
// Given
const orgGid = 'gid://shopify/Organization/123'
const shopDomain = 'my-production-store.myshopify.com'
const token = 'business-platform-token'
const emptyResponse: FetchStoreByDomainQuery = {
organization: {
id: orgGid,
name: 'Org 123',
accessibleShops: {edges: []},
currentUser: {organizationPermissions: []},
},
}
const productionResponse: FetchStoreByDomainQuery = {
organization: {
id: orgGid,
name: 'Org 123',
accessibleShops: {
edges: [
{
node: {
id: 'gid://BusinessPlatform/Shop/2',
externalId: encodedGidFromShopId('2'),
name: 'My Production Store',
storeType: 'PRODUCTION',
primaryDomain: shopDomain,
shortName: 'my-production-store',
url: `https://${shopDomain}`,
},
},
],
},
currentUser: {organizationPermissions: ['ondemand_access_to_stores']},
},
}
vi.mocked(businessPlatformOrganizationsRequestDoc)
.mockResolvedValueOnce(emptyResponse)
.mockResolvedValueOnce(productionResponse)

const client = AppManagementClient.getInstance()
client.businessPlatformToken = () => Promise.resolve(token)

// When
const result = await client.storeByDomain(orgGid, shopDomain, ['APP_DEVELOPMENT', 'PRODUCTION'])

// Then
expect(vi.mocked(businessPlatformOrganizationsRequestDoc)).toHaveBeenNthCalledWith(1, {
query: FetchStoreByDomain,
token,
organizationId: '123',
variables: {
domain: shopDomain,
filters: [
{field: 'STORE_TYPE', operator: 'EQUALS', value: 'app_development'},
{field: 'STORE_STATUS', operator: 'EQUALS', value: 'ACTIVE'},
],
},
unauthorizedHandler: {
type: 'token_refresh',
handler: expect.any(Function),
},
})
expect(vi.mocked(businessPlatformOrganizationsRequestDoc)).toHaveBeenNthCalledWith(2, {
query: FetchStoreByDomain,
token,
organizationId: '123',
variables: {
domain: shopDomain,
filters: [
{field: 'STORE_TYPE', operator: 'EQUALS', value: 'production'},
{field: 'STORE_STATUS', operator: 'EQUALS', value: 'ACTIVE'},
],
},
unauthorizedHandler: {
type: 'token_refresh',
handler: expect.any(Function),
},
})
expect(result).toMatchObject({
shopDomain,
shopName: 'My Production Store',
provisionable: true,
storeType: 'PRODUCTION',
})
})

test('returns undefined when no active stores match the requested filters', async () => {
// Given
vi.mocked(businessPlatformOrganizationsRequestDoc).mockResolvedValueOnce({
organization: {
id: 'gid://shopify/Organization/123',
name: 'Org 123',
accessibleShops: {edges: []},
currentUser: {organizationPermissions: []},
},
})

const client = AppManagementClient.getInstance()
client.businessPlatformToken = () => Promise.resolve('business-platform-token')

// When
const result = await client.storeByDomain('gid://shopify/Organization/123', 'missing-store.myshopify.com', [
'APP_DEVELOPMENT',
])

// Then
expect(result).toBeUndefined()
expect(vi.mocked(businessPlatformOrganizationsRequestDoc)).toHaveBeenCalledWith({
query: FetchStoreByDomain,
token: 'business-platform-token',
organizationId: '123',
variables: {
domain: 'missing-store.myshopify.com',
filters: [
{field: 'STORE_TYPE', operator: 'EQUALS', value: 'app_development'},
{field: 'STORE_STATUS', operator: 'EQUALS', value: 'ACTIVE'},
],
},
unauthorizedHandler: {
type: 'token_refresh',
handler: expect.any(Function),
},
})
})
})

describe('ensureUserAccessToStore', () => {
test('ensures user access to store', async () => {
// Given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1486,11 +1486,11 @@ function toUserError(err: CreateAppVersionMutation['appVersionCreate']['userErro
return {...err, details}
}

// Keep explicit domain lookup broader than ListAppDevStores for now.
// If APP_DEVELOPMENT lookups also need to exclude deleted/inactive stores here,
// add STORE_STATUS=ACTIVE only for that store type and cover mixed storeTypes callers.
function storeByDomainFilters(storeType: Store) {
return [{field: 'STORE_TYPE' as const, operator: 'EQUALS' as const, value: storeType.toLowerCase()}]
return [
{field: 'STORE_TYPE' as const, operator: 'EQUALS' as const, value: storeType.toLowerCase()},
{field: 'STORE_STATUS' as const, operator: 'EQUALS' as const, value: 'ACTIVE'},
]
}

function isStoreProvisionable(permissions: string[]) {
Expand Down
Loading