Skip to content

Commit f732fe3

Browse files
committed
[eas-cli] Add Convex team command
1 parent 5c5bd7c commit f732fe3

2 files changed

Lines changed: 122 additions & 0 deletions

File tree

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { getMockOclifConfig } from '../../../../__tests__/commands/utils';
2+
import { ExpoGraphqlClient } from '../../../../commandUtils/context/contextUtils/createGraphqlClient';
3+
import { testProjectId } from '../../../../credentials/__tests__/fixtures-constants';
4+
import { ConvexQuery } from '../../../../graphql/queries/ConvexQuery';
5+
import { ConvexTeamConnectionData } from '../../../../graphql/types/ConvexTeamConnection';
6+
import Log from '../../../../log';
7+
import { getOwnerAccountForProjectIdAsync } from '../../../../project/projectUtils';
8+
import IntegrationsConvexTeam from '../team';
9+
10+
jest.mock('../../../../graphql/queries/ConvexQuery');
11+
jest.mock('../../../../project/projectUtils');
12+
jest.mock('../../../../log');
13+
14+
describe(IntegrationsConvexTeam, () => {
15+
const graphqlClient = {} as ExpoGraphqlClient;
16+
const mockConfig = getMockOclifConfig();
17+
const testAccountId = 'test-account-id';
18+
const testAccountName = 'testuser';
19+
20+
const mockAccount = {
21+
id: testAccountId,
22+
name: testAccountName,
23+
ownerUserActor: { id: 'test-user-id', username: testAccountName },
24+
users: [{ role: 'OWNER' as any, actor: { id: 'test-user-id' } }],
25+
};
26+
27+
const mockConnection: ConvexTeamConnectionData = {
28+
id: 'connection-1',
29+
convexTeamIdentifier: 'team-123',
30+
convexTeamName: 'Test Team',
31+
convexTeamSlug: 'test-team',
32+
createdAt: '2024-01-01T00:00:00.000Z',
33+
updatedAt: '2024-01-01T00:00:00.000Z',
34+
invitedAt: null,
35+
invitedEmail: null,
36+
};
37+
38+
function createCommand(): IntegrationsConvexTeam {
39+
const command = new IntegrationsConvexTeam([], mockConfig);
40+
jest.spyOn(command as any, 'getContextAsync').mockReturnValue({
41+
privateProjectConfig: {
42+
projectId: testProjectId,
43+
},
44+
loggedIn: { graphqlClient },
45+
} as never);
46+
return command;
47+
}
48+
49+
beforeEach(() => {
50+
jest.resetAllMocks();
51+
jest.spyOn(Log, 'log').mockImplementation(() => {});
52+
jest.spyOn(Log, 'warn').mockImplementation(() => {});
53+
jest.spyOn(Log, 'newLine').mockImplementation(() => {});
54+
jest.mocked(getOwnerAccountForProjectIdAsync).mockResolvedValue(mockAccount as any);
55+
});
56+
57+
it('prints linked Convex team metadata', async () => {
58+
jest
59+
.mocked(ConvexQuery.getConvexTeamConnectionsByAccountIdAsync)
60+
.mockResolvedValue([mockConnection]);
61+
62+
await createCommand().runAsync();
63+
64+
expect(Log.log).toHaveBeenCalledWith(
65+
expect.stringContaining('Convex teams linked to @testuser')
66+
);
67+
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('team-123'));
68+
});
69+
70+
it('prints an empty state when no Convex teams are linked', async () => {
71+
jest.mocked(ConvexQuery.getConvexTeamConnectionsByAccountIdAsync).mockResolvedValue([]);
72+
73+
await createCommand().runAsync();
74+
75+
expect(Log.warn).toHaveBeenCalledWith(expect.stringContaining('No Convex team is linked'));
76+
});
77+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import chalk from 'chalk';
2+
3+
import EasCommand from '../../../commandUtils/EasCommand';
4+
import { formatConvexTeamConnection, logNoConvexTeams } from '../../../commandUtils/convex';
5+
import { ConvexQuery } from '../../../graphql/queries/ConvexQuery';
6+
import Log from '../../../log';
7+
import { getOwnerAccountForProjectIdAsync } from '../../../project/projectUtils';
8+
9+
export default class IntegrationsConvexTeam extends EasCommand {
10+
static override description =
11+
"display Convex teams linked to the current Expo app's owner account";
12+
13+
static override contextDefinition = {
14+
...this.ContextOptions.ProjectConfig,
15+
};
16+
17+
async runAsync(): Promise<void> {
18+
const {
19+
privateProjectConfig: { projectId },
20+
loggedIn: { graphqlClient },
21+
} = await this.getContextAsync(IntegrationsConvexTeam, {
22+
nonInteractive: false,
23+
withServerSideEnvironment: null,
24+
});
25+
26+
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
27+
const connections = await ConvexQuery.getConvexTeamConnectionsByAccountIdAsync(
28+
graphqlClient,
29+
account.id
30+
);
31+
32+
if (connections.length === 0) {
33+
logNoConvexTeams(account.name);
34+
return;
35+
}
36+
37+
Log.log(chalk.bold(`Convex teams linked to @${account.name}`));
38+
for (const [index, connection] of connections.entries()) {
39+
if (index > 0) {
40+
Log.newLine();
41+
}
42+
Log.log(formatConvexTeamConnection(connection));
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)