Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 src/modules/auth/components/organizationSetup.component.vue
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,14 @@ export default {
if (!organizationId) return;

this.requestLoading = true;
this.error = null;
const organizationsStore = useOrganizationsStore();
try {
await organizationsStore.createJoinRequest(organizationId);
this.requestSent = true;
this.$emit('requestSent', this.suggestedOrganization);
} catch (err) {
console.error(err);
this.error = err?.response?.data?.message || err?.message || 'Could not send join request. Please try again.';
} finally {
this.requestLoading = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import { createPinia, setActivePinia } from 'pinia';
import { createVuetify } from 'vuetify';

const createOrganizationMock = vi.hoisted(() => vi.fn());
const createJoinRequestMock = vi.hoisted(() => vi.fn());
vi.mock('../../organizations/stores/organizations.store', () => ({
useOrganizationsStore: () => ({ createOrganization: createOrganizationMock }),
useOrganizationsStore: () => ({
createOrganization: createOrganizationMock,
createJoinRequest: createJoinRequestMock,
}),
}));

import AuthOrganizationSetupComponent from '../components/organizationSetup.component.vue';
Expand All @@ -30,10 +34,12 @@ const makeFormStub = (valid = true) => ({
/**
* Mount the organization setup component with Vuetify and stubbed form.
* @param {object} formStub - VForm component definition controlling validation outcome.
* @param {object} props - Component props (e.g. suggestedOrganization).
* @returns {import('@vue/test-utils').VueWrapper} mounted wrapper
*/
const mountComponent = (formStub = makeFormStub()) =>
const mountComponent = (formStub = makeFormStub(), props = {}) =>
mount(AuthOrganizationSetupComponent, {
props,
global: {
plugins: [createVuetify()],
mocks: { config: mockConfig },
Expand All @@ -45,6 +51,7 @@ describe('auth.organizationSetup.component', () => {
beforeEach(() => {
setActivePinia(createPinia());
createOrganizationMock.mockReset();
createJoinRequestMock.mockReset();
});

it('renders the organization name field and heading', async () => {
Expand Down Expand Up @@ -192,4 +199,91 @@ describe('auth.organizationSetup.component', () => {
await wrapper.vm.submit();
expect(wrapper.vm.error).toBeNull();
});

// --- request to join an existing organization ---

const suggestedOrg = { name: 'Acme Inc.', _id: 'org-1' };

it('calls createJoinRequest with the organization id and leaves no error on success', async () => {
createJoinRequestMock.mockResolvedValueOnce(undefined);

const wrapper = mountComponent(makeFormStub(), { suggestedOrganization: suggestedOrg });
await flushPromises();

await wrapper.vm.requestJoin();

expect(createJoinRequestMock).toHaveBeenCalledTimes(1);
expect(createJoinRequestMock).toHaveBeenCalledWith('org-1');
expect(wrapper.vm.error).toBeNull();
});

it('sets requestSent and emits requestSent on a successful join request', async () => {
createJoinRequestMock.mockResolvedValueOnce(undefined);

const wrapper = mountComponent(makeFormStub(), { suggestedOrganization: suggestedOrg });
await flushPromises();

await wrapper.vm.requestJoin();

expect(wrapper.vm.requestSent).toBe(true);
expect(wrapper.emitted('requestSent')).toBeTruthy();
expect(wrapper.emitted('requestSent')[0]).toEqual([suggestedOrg]);
});

it('sets error from response data message on createJoinRequest failure', async () => {
const apiError = { response: { data: { message: 'You are already a member' } } };
createJoinRequestMock.mockRejectedValueOnce(apiError);

const wrapper = mountComponent(makeFormStub(), { suggestedOrganization: suggestedOrg });
await flushPromises();

await wrapper.vm.requestJoin();

expect(wrapper.vm.error).toBe('You are already a member');
expect(wrapper.vm.requestSent).toBe(false);
});

it('falls back to err.message when a join request has no response data message', async () => {
createJoinRequestMock.mockRejectedValueOnce(new Error('Network error'));

const wrapper = mountComponent(makeFormStub(), { suggestedOrganization: suggestedOrg });
await flushPromises();

await wrapper.vm.requestJoin();

expect(wrapper.vm.error).toBe('Network error');
});

it('falls back to a generic join message when the error has no message', async () => {
createJoinRequestMock.mockRejectedValueOnce({});

const wrapper = mountComponent(makeFormStub(), { suggestedOrganization: suggestedOrg });
await flushPromises();

await wrapper.vm.requestJoin();

expect(wrapper.vm.error).toBe('Could not send join request. Please try again.');
});

it('clears a stale error at the start of a join request', async () => {
const wrapper = mountComponent(makeFormStub(), { suggestedOrganization: suggestedOrg });
await flushPromises();

// A prior create-org failure left an error on the component
wrapper.vm.error = 'Could not create organization. Please try again.';

createJoinRequestMock.mockResolvedValueOnce(undefined);
await wrapper.vm.requestJoin();

expect(wrapper.vm.error).toBeNull();
});

it('does nothing when there is no suggested organization', async () => {
const wrapper = mountComponent();
await flushPromises();

await wrapper.vm.requestJoin();

expect(createJoinRequestMock).not.toHaveBeenCalled();
});
});
Loading