Add data testing attributes and adapt tests for team account invitations

This commit adds data testing attributes to key elements in the team account invitations features. It also modifies e2e tests to make use of these attributes. Additionally, it introduces minor tweaks to other parts of the system to better facilitate testing, such as adjustments in timeouts and update of some log messages.
This commit is contained in:
giancarlo
2024-04-13 15:27:21 +08:00
parent 24e5c0debd
commit b6b9a9462f
15 changed files with 219 additions and 62 deletions

View File

@@ -188,7 +188,9 @@ export function AccountSelector({
>
{(accounts ?? []).map((account) => (
<CommandItem
data-test={'account-selector-team-' + account.value}
data-test={'account-selector-team'}
data-name={account.label}
data-slug={account.value}
className={'group'}
key={account.value}
value={account.value ?? ''}

View File

@@ -60,7 +60,11 @@ export function AcceptInvitationContainer(props: {
</div>
<div className={'flex flex-col space-y-2.5'}>
<form className={'w-full'} action={acceptInvitationAction}>
<form
data-test={'join-team-form'}
className={'w-full'}
action={acceptInvitationAction}
>
<input type="hidden" name={'inviteToken'} value={props.inviteToken} />
<input

View File

@@ -65,7 +65,11 @@ export function AccountInvitationsTable({
placeholder={t(`searchInvitations`)}
/>
<DataTable columns={columns} data={filteredInvitations} />
<DataTable
data-cy={'invitations-table'}
columns={columns}
data={filteredInvitations}
/>
</div>
);
}
@@ -87,7 +91,10 @@ function useGetColumns(permissions: {
const email = member.email;
return (
<span className={'flex items-center space-x-4 text-left'}>
<span
data-test={'invitation-email'}
className={'flex items-center space-x-4 text-left'}
>
<span>
<ProfileAvatar text={email} />
</span>
@@ -166,19 +173,28 @@ function ActionsDropdown({
<DropdownMenuContent>
<If condition={permissions.canUpdateInvitation}>
<DropdownMenuItem onClick={() => setIsUpdatingRole(true)}>
<DropdownMenuItem
data-test={'update-invitation-trigger'}
onClick={() => setIsUpdatingRole(true)}
>
<Trans i18nKey={'teams:updateInvitation'} />
</DropdownMenuItem>
<If condition={getIsInviteExpired(invitation.expires_at)}>
<DropdownMenuItem onClick={() => setIsRenewingInvite(true)}>
<DropdownMenuItem
data-test={'renew-invitation-trigger'}
onClick={() => setIsRenewingInvite(true)}
>
<Trans i18nKey={'teams:renewInvitation'} />
</DropdownMenuItem>
</If>
</If>
<If condition={permissions.canRemoveInvitation}>
<DropdownMenuItem onClick={() => setIsDeletingInvite(true)}>
<DropdownMenuItem
data-test={'remove-invitation-trigger'}
onClick={() => setIsDeletingInvite(true)}
>
<Trans i18nKey={'teams:removeInvitation'} />
</DropdownMenuItem>
</If>

View File

@@ -66,7 +66,7 @@ function DeleteInvitationForm({
};
return (
<form action={onInvitationRemoved}>
<form data-test={'delete-invitation-form'} action={onInvitationRemoved}>
<div className={'flex flex-col space-y-6'}>
<p className={'text-muted-foreground text-sm'}>
<Trans i18nKey={'common:modalConfirmationQuestion'} />
@@ -82,7 +82,7 @@ function DeleteInvitationForm({
</AlertDialogCancel>
<Button
data-test={'confirm-delete-invitation'}
type={'submit'}
variant={'destructive'}
disabled={isSubmitting}
>

View File

@@ -9,7 +9,7 @@ export function InvitationSubmitButton(props: { accountName: string }) {
const { pending } = useFormStatus();
return (
<Button className={'w-full'} disabled={pending}>
<Button type={'submit'} className={'w-full'} disabled={pending}>
<Trans
i18nKey={pending ? 'teams:joiningTeam' : 'teams:joinTeam'}
values={{

View File

@@ -25,7 +25,7 @@ import {
import { If } from '@kit/ui/if';
import { Trans } from '@kit/ui/trans';
import { UpdateMemberRoleSchema } from '../../schema/update-member-role.schema';
import { RoleSchema } from '../../schema/update-member-role.schema';
import { updateInvitationAction } from '../../server/actions/team-invitations-server-actions';
import { MembershipRoleSelector } from '../members/membership-role-selector';
import { RolesDataProvider } from '../members/roles-data-provider';
@@ -47,37 +47,30 @@ export const UpdateInvitationDialog: React.FC<{
userRoleHierarchy,
account,
}) => {
return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>
<Trans i18nKey={'teams:updateMemberRoleModalHeading'} />
</DialogTitle>
return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>
<Trans i18nKey={'teams:updateMemberRoleModalHeading'} />
</DialogTitle>
<DialogDescription>
<Trans i18nKey={'teams:updateMemberRoleModalDescription'} />
</DialogDescription>
</DialogHeader>
<DialogDescription>
<Trans i18nKey={'teams:updateMemberRoleModalDescription'} />
</DialogDescription>
</DialogHeader>
<RolesDataProvider
accountId={account}
maxRoleHierarchy={userRoleHierarchy}
>
{(roles) => (
<UpdateInvitationForm
account={account}
invitationId={invitationId}
userRole={userRole}
userRoleHierarchy={roles.length}
setIsOpen={setIsOpen}
/>
)}
</RolesDataProvider>
</DialogContent>
</Dialog>
);
};
<UpdateInvitationForm
account={account}
invitationId={invitationId}
userRole={userRole}
userRoleHierarchy={userRoleHierarchy}
setIsOpen={setIsOpen}
/>
</DialogContent>
</Dialog>
);
};
function UpdateInvitationForm({
account,
@@ -113,7 +106,7 @@ function UpdateInvitationForm({
const form = useForm({
resolver: zodResolver(
UpdateMemberRoleSchema.refine(
RoleSchema.refine(
(data) => {
return data.role !== userRole;
},
@@ -133,6 +126,7 @@ function UpdateInvitationForm({
return (
<Form {...form}>
<form
data-test={'update-invitation-form'}
onSubmit={form.handleSubmit(onSubmit)}
className={'flex flex-col space-y-6'}
>
@@ -177,7 +171,7 @@ function UpdateInvitationForm({
}}
/>
<Button data-test={'confirm-update-member-role'} disabled={pending}>
<Button type={'submit'} disabled={pending}>
<Trans i18nKey={'teams:updateRoleSubmitLabel'} />
</Button>
</form>

View File

@@ -17,7 +17,7 @@ export class AccountPerSeatBillingService {
logger.info(
ctx,
`Getting per-seat subscription item for account ${accountId}...`,
`Retrieving per-seat subscription item for account ${accountId}...`,
);
const { data, error } = await this.client
@@ -34,7 +34,7 @@ export class AccountPerSeatBillingService {
`,
)
.eq('account_id', accountId)
.eq('subscription_items.type', 'per-seat')
.eq('subscription_items.type', 'per_seat')
.maybeSingle();
if (error) {
@@ -52,7 +52,7 @@ export class AccountPerSeatBillingService {
if (!data?.subscription_items) {
logger.info(
ctx,
`No per-seat subscription item found for account ${accountId}. Exiting...`,
`Account is not subscribed to a per-seat subscription. Exiting...`,
);
return;

View File

@@ -59,6 +59,7 @@ export function DataTable<TData, TValue>({
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-row-id={row.id}
data-state={row.getIsSelected() && 'selected'}
>
{row.getVisibleCells().map((cell) => (