Skip to content

Commit

Permalink
Add tests to EnvironmentVariableGet
Browse files Browse the repository at this point in the history
  • Loading branch information
khamilowicz committed Sep 24, 2024
1 parent ef4327f commit c503dfc
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 33 deletions.
2 changes: 1 addition & 1 deletion packages/eas-cli/src/commandUtils/flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const EasNonInteractiveAndJsonFlags = {
}),
};

const EasEnvironmentFlagParameters = {
export const EasEnvironmentFlagParameters = {
description: "Environment variable's environment",
parse: upperCaseAsync,
options: mapToLowercase([
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { Config } from '@oclif/core';

import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { testProjectId } from '../../../credentials/__tests__/fixtures-constants';
import {
EnvironmentVariableEnvironment,
EnvironmentVariableScope,
EnvironmentVariableVisibility,
} from '../../../graphql/generated';
import { EnvironmentVariablesQuery } from '../../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../../log';
import { promptVariableEnvironmentAsync, promptVariableNameAsync } from '../../../utils/prompts';
import EnvironmentVariableGet from '../get';

jest.mock('../../../graphql/mutations/EnvironmentVariableMutation');
jest.mock('../../../graphql/queries/AppQuery');
jest.mock('../../../graphql/queries/EnvironmentVariablesQuery');
jest.mock('../../../utils/prompts');

describe(EnvironmentVariableGet, () => {
const graphqlClient = {} as any as ExpoGraphqlClient;
const mockConfig = {} as unknown as Config;
const mockVariables = [
{
id: 'var1',
name: 'TEST_VAR_1',
value: 'value1',
environments: [EnvironmentVariableEnvironment.Production],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
scope: EnvironmentVariableScope.Project,
visibility: EnvironmentVariableVisibility.Public,
},
];

it('retrieves environment variables successfully', async () => {
jest
.mocked(EnvironmentVariablesQuery.byAppIdWithSensitiveAsync)
.mockResolvedValueOnce(mockVariables);
jest.spyOn(Log, 'log').mockImplementation(() => {});

const command = new EnvironmentVariableGet(['--variable-name', 'TEST_VAR_1'], mockConfig);

// @ts-expect-error
jest.spyOn(command, 'getContextAsync').mockReturnValue({
loggedIn: { graphqlClient },
privateProjectConfig: { projectId: testProjectId },
});

await command.runAsync();

expect(EnvironmentVariablesQuery.byAppIdWithSensitiveAsync).toHaveBeenCalledWith(
graphqlClient,
{
appId: testProjectId,
environment: undefined,
filterNames: ['TEST_VAR_1'],
}
);
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
});

it('handles errors during retrieval', async () => {
const errorMessage =
"Variable name is required. Run the command with '--variable-name VARIABLE_NAME' flag";

const command = new EnvironmentVariableGet([], mockConfig);

// @ts-expect-error
jest.spyOn(command, 'getContextAsync').mockReturnValue({
loggedIn: { graphqlClient },
privateProjectConfig: { projectId: testProjectId },
});

await expect(command.runAsync()).rejects.toThrow(errorMessage);
});

it('prompts for variable name and environment if the name is ambigous', async () => {
jest
.mocked(promptVariableEnvironmentAsync)
.mockResolvedValueOnce(EnvironmentVariableEnvironment.Production);
jest.mocked(promptVariableNameAsync).mockResolvedValueOnce('TEST_VAR_1');

const command = new EnvironmentVariableGet([], mockConfig);

// @ts-expect-error
jest.spyOn(command, 'getContextAsync').mockReturnValue({
loggedIn: { graphqlClient },
privateProjectConfig: { projectId: testProjectId },
});
jest.mocked(EnvironmentVariablesQuery.byAppIdWithSensitiveAsync).mockResolvedValueOnce([
...mockVariables,
{
id: 'var2',
name: 'TEST_VAR_1',
value: 'value1',
environments: [EnvironmentVariableEnvironment.Development],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
scope: EnvironmentVariableScope.Project,
visibility: EnvironmentVariableVisibility.Public,
},
]);
await command.runAsync();

expect(promptVariableEnvironmentAsync).toHaveBeenCalled();
expect(promptVariableNameAsync).toHaveBeenCalled();
});
});
86 changes: 54 additions & 32 deletions packages/eas-cli/src/commands/env/get.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Flags } from '@oclif/core';
import assert from 'assert';
import chalk from 'chalk';

import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import {
EASEnvironmentFlag,
EASNonInteractiveFlag,
EASVariableFormatFlag,
EASVariableScopeFlag,
EasEnvironmentFlagParameters,
} from '../../commandUtils/flags';
import {
EnvironmentVariableEnvironment,
Expand All @@ -20,8 +21,8 @@ import { promptVariableEnvironmentAsync, promptVariableNameAsync } from '../../u
import { formatVariable } from '../../utils/variableUtils';

type GetFlags = {
name?: string;
environment?: EnvironmentVariableEnvironment;
'variable-name'?: string;
'variable-environment'?: EnvironmentVariableEnvironment;
'non-interactive': boolean;
format?: string;
scope: EnvironmentVariableScope;
Expand All @@ -38,21 +39,24 @@ export default class EnvironmentVariableGet extends EasCommand {
};

static override flags = {
name: Flags.string({
'variable-name': Flags.string({
description: 'Name of the variable',
}),
'variable-environment': Flags.enum<EnvironmentVariableEnvironment>({
...EasEnvironmentFlagParameters,
description: 'Current environment of the variable',
}),
...EASVariableFormatFlag,
...EASVariableScopeFlag,
...EASNonInteractiveFlag,
...EASEnvironmentFlag,
};

async runAsync(): Promise<void> {
const { flags } = await this.parse(EnvironmentVariableGet);

let {
environment,
name,
'variable-environment': environment,
'variable-name': name,
'non-interactive': nonInteractive,
format,
scope,
Expand All @@ -69,15 +73,41 @@ export default class EnvironmentVariableGet extends EasCommand {
name = await promptVariableNameAsync(nonInteractive);
}

if (!environment && scope === EnvironmentVariableScope.Project) {
environment = await promptVariableEnvironmentAsync({ nonInteractive });
}
const variable = await getVariableAsync(graphqlClient, scope, projectId, name, environment);
const variables = await getVariablesAsync(graphqlClient, scope, projectId, name, environment);

if (!variable) {
if (variables.length === 0) {
Log.error(`Variable with name "${name}" not found`);
return;
}

let variable;

if (variables.length > 1) {
if (!environment) {
const availableEnvironments = variables.reduce<EnvironmentVariableEnvironment[]>(
(acc, v) => [...acc, ...(v.environments ?? [])],
[] as EnvironmentVariableEnvironment[]
);

environment = await promptVariableEnvironmentAsync({
nonInteractive,
multiple: false,
availableEnvironments,
});
}

assert(environment, 'Environment is required.');

const variableInEnvironment = variables.find(v => v.environments?.includes(environment!));
if (!variableInEnvironment) {
throw new Error(`Variable with name "${name}" not found in environment "${environment}"`);
}

variable = variableInEnvironment;
} else {
variable = variables[0];
}

if (!variable.value) {
throw new Error(
`${chalk.bold(
Expand All @@ -94,56 +124,48 @@ export default class EnvironmentVariableGet extends EasCommand {
}

private validateFlags(flags: GetFlags): GetFlags {
if (flags.environment && flags.scope === EnvironmentVariableScope.Shared) {
throw new Error(`Unexpected argument: --environment can only be used with project variables`);
}
if (flags['non-interactive']) {
if (!flags.name) {
throw new Error('Variable name is required. Run the command with --name flag.');
if (!flags['variable-name']) {
throw new Error('Variable name is required. Run the command with --variable-name flag.');
}
if (!flags.scope) {
throw new Error('Scope is required. Run the command with --scope flag.');
}
if (!flags.environment && flags.scope === EnvironmentVariableScope.Project) {
if (!flags['variable-environment']) {
throw new Error('Environment is required.');
}
}
return flags;
}
}

async function getVariableAsync(
async function getVariablesAsync(
graphqlClient: ExpoGraphqlClient,
scope: string,
projectId: string,
name: string | undefined,
environment: EnvironmentVariableEnvironment | undefined
): Promise<EnvironmentVariableFragment | null> {
if (!environment && scope === EnvironmentVariableScope.Project) {
throw new Error('Environment is required.');
}
): Promise<EnvironmentVariableFragment[]> {
if (!name) {
throw new Error("Variable name is required. Run the command with '--name VARIABLE_NAME' flag.");
throw new Error(
"Variable name is required. Run the command with '--variable-name VARIABLE_NAME' flag."
);
}
if (environment && scope === EnvironmentVariableScope.Project) {
if (scope === EnvironmentVariableScope.Project) {
const appVariables = await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync(graphqlClient, {
appId: projectId,
environment,
filterNames: [name],
});
return appVariables[0];
}

if (scope === EnvironmentVariableScope.Shared) {
return appVariables;
} else {
const sharedVariables = await EnvironmentVariablesQuery.sharedWithSensitiveAsync(
graphqlClient,
{
appId: projectId,
filterNames: [name],
}
);
return sharedVariables[0];
return sharedVariables;
}

return null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const EnvironmentVariablesQuery = {
id
name
value
environments
}
}
}
Expand Down Expand Up @@ -167,6 +168,7 @@ export const EnvironmentVariablesQuery = {
id
name
value
environments
}
}
}
Expand Down

0 comments on commit c503dfc

Please sign in to comment.