Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(e2e): teamAdmin permission tests #2230

Merged
merged 18 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from 15 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
3 changes: 2 additions & 1 deletion e2e/tests/api-driven/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"axios": "^1.4.0",
"dotenv": "^16.3.1",
"dotenv-expand": "^10.0.0",
"graphql-request": "^6.1.0",
"graphql": "^16.8.1",
"graphql-tag": "^2.12.6",
"jsonwebtoken": "^9.0.2",
"nock": "^13.3.1"
},
Expand Down
40 changes: 14 additions & 26 deletions e2e/tests/api-driven/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 50 additions & 18 deletions e2e/tests/api-driven/src/permissions/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { DocumentNode, Kind } from "graphql/language";
import { $admin, getClient } from "../client";
import { CustomWorld } from "./steps";
import { queries } from "./queries";
import { createFlow, createTeam, createUser } from "../globalHelpers";

export type Action = "insert" | "update" | "delete" | "select";
export type Table = keyof typeof queries;

interface PerformGQLQueryArgs {
world: CustomWorld;
action: string;
table: string;
action: Action;
table: Table;
}

export const addUserToTeam = async (userId: number, teamId: number) => {
Expand All @@ -24,26 +28,27 @@
};

export const setup = async () => {
const user1Id = await createUser({ email: "[email protected]" });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think helen & mel previously reported an annoying issue where e2e test emails using the @opensystemslab.io domain were causing bounced errors in the enquiries inbox? can we use a harmless @example.com or something instead?

const teamId1 = await createTeam({ name: "E2E Team 1", slug: "e2e-team1" });
const team1FlowId = await createFlow({
teamId: teamId1,
slug: "team-1-flow",
});

const user2Id = await createUser({ email: "[email protected]" });
const teamId2 = await createTeam({ name: "E2E Team 2", slug: "e2e-team2" });
Copy link
Member

@jessicamcinchak jessicamcinchak Sep 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double checking i understand this: in overall setup, we create two users who are by default not a platform admin and they also do not have roles on either teamId1 or teamId2? then later in individual test suites, you're creating & cleaning up team memberships and toggling permissions?

i'm wondering a bit if it'd be clearer to setup more explicitly with something like e2e-platform-admin@.. etc rather than vague user-1, user-2 etc? definitely not a showstopper though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I appreciate this is an unclear point - team1 and team2 are quite vague/meaningless names but I needed something to differentiate (I was also considering red/blue or something to make it slightly more distinct).

The intention is that there are -

  • Two teams
  • One TeamEditor of each team
  • We test that teamEditor1 can access team1 resources
  • We test that teamEditor2 cannot access team1 resources

I'll add comments to explicitly explain the setup here 👍

const user1 = {
id: await createUser({ email: "[email protected]" }),
email: "[email protected]",
};
const user2 = {
id: await createUser({ email: "[email protected]" }),
email: "[email protected]",
};
const team1Flow = await createFlow({ teamId: teamId1, slug: "team-1-flow" });
const team2Flow = await createFlow({ teamId: teamId2, slug: "team-2-flow" });
const team2FlowId = await createFlow({
teamId: teamId2,
slug: "team-2-flow",
});

const world = {
user1Id,
teamId1,
team1FlowId,
user2Id,
teamId2,
user1,
user2,
team1Flow,
team2Flow,
team2FlowId,
};

return world;
Expand All @@ -55,7 +60,34 @@
table,
}: PerformGQLQueryArgs) => {
const query = queries[table][action];
const client = (await getClient(world.activeUser.email)).client;
const result = await client.request(query, { teamId1: world.teamId1 });
const variables = buildVariables(query, world);
const client = (await getClient(world.activeUserEmail)).client;
const { result } = await client.request<Record<"result", any>>(

Check warning on line 65 in e2e/tests/api-driven/src/permissions/helpers.ts

View workflow job for this annotation

GitHub Actions / E2E tests

Unexpected any. Specify a different type

Check warning on line 65 in e2e/tests/api-driven/src/permissions/helpers.ts

View workflow job for this annotation

GitHub Actions / E2E tests

Unexpected any. Specify a different type
query,
variables,
);
return result;
};

/**
* Parse GQL query to extract variables required for query
* Match with values from our test world to construct variables for query
*/
const buildVariables = (query: DocumentNode, world: CustomWorld) => {
const variables = {};
const definitionNode = query.definitions[0];

if (definitionNode.kind !== Kind.OPERATION_DEFINITION) return variables;
if (!definitionNode.variableDefinitions) return variables;

Object.keys(world).forEach((key) => {
const isVariableUsedInQuery = definitionNode.variableDefinitions!.find(
(varDef) => varDef.variable.name.value === key,
);
if (isVariableUsedInQuery) {
variables[key] = world[key];
}
});

return variables;
};
27 changes: 23 additions & 4 deletions e2e/tests/api-driven/src/permissions/queries/flows.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { gql } from "graphql-request";
import { gql } from "graphql-tag";

export const INSERT_FLOW_QUERY = gql`
mutation InsertFlowE2E($teamId1: Int) {
insert_flows(
mutation InsertFlowE2E($team1Id: Int) {
result: insert_flows(
objects: {
data: "{hello: 'world'}"
slug: "e2e-test-flow"
team_id: $teamId1
team_id: $team1Id
}
) {
returning {
Expand All @@ -15,3 +15,22 @@ export const INSERT_FLOW_QUERY = gql`
}
}
`;

export const UPDATE_FLOW_QUERY = gql`
mutation UpdateFlowE2E($team1FlowId: uuid!) {
result: update_flows_by_pk(
pk_columns: { id: $team1FlowId }
_set: { data: "{hello: 'world2'}" }
) {
id
}
}
`;

export const DELETE_FLOW_QUERY = gql`
mutation DeleteFlowE2E($team1FlowId: uuid!) {
result: delete_flows_by_pk(id: $team1FlowId) {
id
}
}
`;
27 changes: 25 additions & 2 deletions e2e/tests/api-driven/src/permissions/queries/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
import { INSERT_FLOW_QUERY } from "./flows";
import {
DELETE_FLOW_QUERY,
INSERT_FLOW_QUERY,
UPDATE_FLOW_QUERY,
} from "./flows";
import { INSERT_OPERATION_QUERY, UPDATE_OPERATION_QUERY } from "./operations";
import { INSERT_PUBLISHED_FLOW_QUERY } from "./publishedFlows";
import { SELECT_TEAM_MEMBERS_QUERY } from "./teamMembers";
import { SELECT_USERS_QUERY } from "./users";

export const queries = {
flows: {
insert: INSERT_FLOW_QUERY,
update: UPDATE_FLOW_QUERY,
delete: DELETE_FLOW_QUERY,
},
};
users: {
select: SELECT_USERS_QUERY,
},
published_flows: {
insert: INSERT_PUBLISHED_FLOW_QUERY,
},
team_members: {
select: SELECT_TEAM_MEMBERS_QUERY,
},
operations: {
insert: INSERT_OPERATION_QUERY,
update: UPDATE_OPERATION_QUERY,
},
} as const;
24 changes: 24 additions & 0 deletions e2e/tests/api-driven/src/permissions/queries/operations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { gql } from "graphql-tag";

export const INSERT_OPERATION_QUERY = gql`
mutation InsertOperationE2E($team1FlowId: uuid!) {
result: insert_operations_one(
object: { data: "{}", flow_id: $team1FlowId }
) {
id
}
}
`;

export const UPDATE_OPERATION_QUERY = gql`
mutation UpdateOperationE2E($team1FlowId: uuid!) {
result: update_operations(
where: { flow_id: { _eq: $team1FlowId } }
_set: { data: "" }
) {
returning {
id
}
}
}
`;
17 changes: 17 additions & 0 deletions e2e/tests/api-driven/src/permissions/queries/publishedFlows.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import gql from "graphql-tag";

export const INSERT_PUBLISHED_FLOW_QUERY = gql`
mutation InsertPublishedFlowsE2E($team1FlowId: uuid!, $activeUserId: Int) {
result: insert_published_flows(
objects: {
data: "{}"
flow_id: $team1FlowId
publisher_id: $activeUserId
}
) {
returning {
id
}
}
}
`;
9 changes: 9 additions & 0 deletions e2e/tests/api-driven/src/permissions/queries/teamMembers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import gql from "graphql-tag";

export const SELECT_TEAM_MEMBERS_QUERY = gql`
query SelectTeamMembersE2E($user1Id: Int) {
result: team_members(where: { user_id: { _eq: $user1Id } }) {
id
}
}
`;
9 changes: 9 additions & 0 deletions e2e/tests/api-driven/src/permissions/queries/users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import gql from "graphql-tag";

export const SELECT_USERS_QUERY = gql`
query SelectUsersE2E($user1Id: Int!) {
result: users_by_pk(id: $user1Id) {
id
}
}
`;
Loading
Loading