From 91b7b4642c84481c488ea1f2486b87002495a73d Mon Sep 17 00:00:00 2001 From: Ariel Caplan Date: Tue, 6 Aug 2024 15:49:56 +0300 Subject: [PATCH] Test flag fetching and template filtering --- .../app-management-client.test.ts | 105 ++++++++++++++---- .../app-management-client.ts | 2 +- .../graphql/organization_beta_flags.ts | 3 +- 3 files changed, 84 insertions(+), 26 deletions(-) diff --git a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.test.ts b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.test.ts index ca3937e5a8..f2c1804b62 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.test.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.test.ts @@ -1,17 +1,45 @@ -import {AppManagementClient, GatedExtensionTemplate, allowedTemplates, diffAppModules} from './app-management-client.js' +import { + AppManagementClient, + GatedExtensionTemplate, + allowedTemplates, + diffAppModules, + encodedGidFromId, +} from './app-management-client.js' import {AppModule} from './app-management-client/graphql/app-version-by-id.js' +import {OrganizationBetaFlagsQuerySchema} from './app-management-client/graphql/organization_beta_flags.js' import {testUIExtension, testRemoteExtensionTemplates, testOrganizationApp} from '../../models/app/app.test-data.js' import {ExtensionInstance} from '../../models/extensions/extension-instance.js' import {describe, expect, test, vi} from 'vitest' import {CLI_KIT_VERSION} from '@shopify/cli-kit/common/version' import {fetch} from '@shopify/cli-kit/node/http' +import {businessPlatformOrganizationsRequest} from '@shopify/cli-kit/node/api/business-platform' vi.mock('@shopify/cli-kit/node/http') +vi.mock('@shopify/cli-kit/node/api/business-platform') const extensionA = await testUIExtension({uid: 'extension-a-uuid'}) const extensionB = await testUIExtension({uid: 'extension-b-uuid'}) const extensionC = await testUIExtension({uid: 'extension-c-uuid'}) +const templateWithoutRules: GatedExtensionTemplate = testRemoteExtensionTemplates[0]! +const allowedTemplate: GatedExtensionTemplate = { + ...testRemoteExtensionTemplates[1]!, + organizationBetaFlags: ['allowedFlag'], + minimumCliVersion: '1.0.0', +} +const templateDisallowedByCliVersion: GatedExtensionTemplate = { + ...testRemoteExtensionTemplates[2]!, + organizationBetaFlags: ['allowedFlag'], + // minimum CLI version is higher than the current CLI version + minimumCliVersion: `1${CLI_KIT_VERSION}`, +} +const templateDisallowedByBetaFlag: GatedExtensionTemplate = { + ...testRemoteExtensionTemplates[3]!, + // organization beta flag is not allowed + organizationBetaFlags: ['notAllowedFlag'], + minimumCliVersion: '1.0.0', +} + function moduleFromExtension(extension: ExtensionInstance): AppModule { return { uuid: extension.uid, @@ -49,21 +77,70 @@ describe('diffAppModules', () => { describe('templateSpecifications', () => { test('returns the templates with sortPriority to enforce order', async () => { // Given - const mockedFetch = vi.fn().mockResolvedValueOnce(Response.json(testRemoteExtensionTemplates)) + const orgApp = testOrganizationApp() + const templates: GatedExtensionTemplate[] = [templateWithoutRules, allowedTemplate] + const mockedFetch = vi.fn().mockResolvedValueOnce(Response.json(templates)) vi.mocked(fetch).mockImplementation(mockedFetch) + const mockedFetchFlagsResponse: OrganizationBetaFlagsQuerySchema = { + organization: { + id: encodedGidFromId(orgApp.organizationId), + flag_allowedFlag: true, + }, + } + vi.mocked(businessPlatformOrganizationsRequest).mockResolvedValueOnce(mockedFetchFlagsResponse) // When const client = new AppManagementClient() - const got = await client.templateSpecifications(testOrganizationApp()) + client.businessPlatformToken = () => Promise.resolve('business-platform-token') + const got = await client.templateSpecifications(orgApp) const gotLabels = got.map((template) => template.name) const gotSortPriorities = got.map((template) => template.sortPriority) // Then - expect(got.length).toEqual(testRemoteExtensionTemplates.length) - expect(gotLabels).toEqual(testRemoteExtensionTemplates.map((template) => template.name)) + expect(got.length).toEqual(templates.length) + expect(gotLabels).toEqual(templates.map((template) => template.name)) expect(gotSortPriorities).toEqual(gotSortPriorities.sort()) }) + test('returns only allowed templates', async () => { + // Given + const orgApp = testOrganizationApp() + const templates: GatedExtensionTemplate[] = [templateWithoutRules, allowedTemplate, templateDisallowedByBetaFlag] + const mockedFetch = vi.fn().mockResolvedValueOnce(Response.json(templates)) + vi.mocked(fetch).mockImplementation(mockedFetch) + const mockedFetchFlagsResponse: OrganizationBetaFlagsQuerySchema = { + organization: { + id: encodedGidFromId(orgApp.organizationId), + flag_allowedFlag: true, + flag_notAllowedFlag: false, + }, + } + vi.mocked(businessPlatformOrganizationsRequest).mockResolvedValueOnce(mockedFetchFlagsResponse) + + // When + const client = new AppManagementClient() + client.businessPlatformToken = () => Promise.resolve('business-platform-token') + const got = await client.templateSpecifications(orgApp) + const gotLabels = got.map((template) => template.name) + + // Then + expect(vi.mocked(businessPlatformOrganizationsRequest)).toHaveBeenCalledWith( + ` + query OrganizationBetaFlags($organizationId: OrganizationID!) { + organization(organizationId: $organizationId) { + id + flag_allowedFlag: hasFeatureFlag(handle: "allowedFlag") + flag_notAllowedFlag: hasFeatureFlag(handle: "notAllowedFlag") + } + }`, + 'business-platform-token', + orgApp.organizationId, + {organizationId: encodedGidFromId(orgApp.organizationId)}, + ) + const expectedAllowedTemplates = [templateWithoutRules, allowedTemplate] + expect(gotLabels).toEqual(expectedAllowedTemplates.map((template) => template.name)) + }) + test('fails with an error message when fetching the specifications list fails', async () => { // Given vi.mocked(fetch).mockRejectedValueOnce(new Error('Failed to fetch')) @@ -80,24 +157,6 @@ describe('templateSpecifications', () => { describe('allowedTemplates', () => { test('filters templates by betas', async () => { // Given - const templateWithoutRules: GatedExtensionTemplate = testRemoteExtensionTemplates[0]! - const allowedTemplate: GatedExtensionTemplate = { - ...testRemoteExtensionTemplates[1]!, - organizationBetaFlags: ['allowedFlag'], - minimumCliVersion: '1.0.0', - } - const templateDisallowedByCliVersion: GatedExtensionTemplate = { - ...testRemoteExtensionTemplates[2]!, - organizationBetaFlags: ['allowedFlag'], - // minimum CLI version is higher than the current CLI version - minimumCliVersion: `1${CLI_KIT_VERSION}`, - } - const templateDisallowedByBetaFlag: GatedExtensionTemplate = { - ...testRemoteExtensionTemplates[3]!, - // organization beta flag is not allowed - organizationBetaFlags: ['notAllowedFlag'], - minimumCliVersion: '1.0.0', - } const templates: GatedExtensionTemplate[] = [ templateWithoutRules, allowedTemplate, diff --git a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts index ccf9582fa0..c41ca59c2c 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts @@ -938,7 +938,7 @@ function createAppVars(name: string, isLaunchable = true, scopesArray?: string[] // just the integer portion of that ID. These functions convert between the two. // 1234 => gid://organization/Organization/1234 => base64 -function encodedGidFromId(id: string): string { +export function encodedGidFromId(id: string): string { const gid = `gid://organization/Organization/${id}` return Buffer.from(gid).toString('base64') } diff --git a/packages/app/src/cli/utilities/developer-platform-client/app-management-client/graphql/organization_beta_flags.ts b/packages/app/src/cli/utilities/developer-platform-client/app-management-client/graphql/organization_beta_flags.ts index f10c1c5142..9890234d91 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/app-management-client/graphql/organization_beta_flags.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/app-management-client/graphql/organization_beta_flags.ts @@ -7,8 +7,7 @@ export function organizationBetaFlagsQuery(flags: string[]): string { id ${flags.map((flag) => `flag_${flag}: hasFeatureFlag(handle: "${flag}")`).join('\n ')} } - } - ` + }` } export interface OrganizationBetaFlagsQueryVariables {