Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,158 @@ describe.each([
});
},
);

/*
Additional tests appended to expand coverage of toggle interactions across E2E, Private, Broadcast, and ReadOnly states.
Testing stack:
- Test runner: Jest
- Libraries: @testing-library/react and @testing-library/user-event
These tests follow the same conventions as the existing suite and focus on user-observable behavior.
*/

describe.each([
['CreateTeamModal', CreateTeamModalOld],
['CreateTeamModal in NavbarV2', CreateTeamModal],
] as const)('%s – additional interactions', (_name: string, CreateTeamModalComponent: CreateTeamModalComponentType) => {
it('E2E enabled + default non-private: Encrypted can be turned ON, Private OFF forces Encrypted OFF+disabled, Private ON re-enables it', async () => {
render(<CreateTeamModalComponent onClose={() => null} />, {
wrapper: mockAppRoot().withSetting('E2E_Enable', true).withSetting('E2E_Enabled_Default_PrivateRooms', false).build(),
});

await userEvent.click(screen.getByText('Advanced_settings'));

const encrypted = screen.getByLabelText('Teams_New_Encrypted_Label') as HTMLInputElement;
const priv = screen.getByLabelText('Teams_New_Private_Label') as HTMLInputElement;

// With E2E enabled and this configuration, Encrypted should be available to the user
expect(encrypted).toBeInTheDocument();
expect(encrypted).toBeEnabled();
expect(encrypted).not.toBeChecked();

// User can turn encryption ON
await userEvent.click(encrypted);
expect(encrypted).toBeChecked();

// Private: ON -> OFF enforces Encrypted OFF + disabled
await userEvent.click(priv);
expect(priv).not.toBeChecked();
expect(encrypted).not.toBeChecked();
expect(encrypted).toBeDisabled();

// Private: OFF -> ON keeps Encrypted OFF but re-enables it
await userEvent.click(priv);
expect(priv).toBeChecked();
expect(encrypted).not.toBeChecked();
expect(encrypted).toBeEnabled();
});

it('non-private: clicking Encrypted does nothing when disabled', async () => {
render(<CreateTeamModalComponent onClose={() => null} />, {
wrapper: mockAppRoot().withSetting('E2E_Enable', true).withSetting('E2E_Enabled_Default_PrivateRooms', true).build(),
});

await userEvent.click(screen.getByText('Advanced_settings'));

const encrypted = screen.getByLabelText('Teams_New_Encrypted_Label') as HTMLInputElement;
const priv = screen.getByLabelText('Teams_New_Private_Label') as HTMLInputElement;

// Switch to non-private
await userEvent.click(priv);
expect(priv).not.toBeChecked();

// Encrypted should be OFF + disabled
expect(encrypted).not.toBeChecked();
expect(encrypted).toBeDisabled();

// Attempting to click should not change state
await userEvent.click(encrypted);
expect(encrypted).not.toBeChecked();
expect(encrypted).toBeDisabled();
});

it('Broadcast toggling does not alter Private state', async () => {
render(<CreateTeamModalComponent onClose={() => null} />, {
wrapper: mockAppRoot().withSetting('E2E_Enable', true).withSetting('E2E_Enabled_Default_PrivateRooms', true).build(),
});

await userEvent.click(screen.getByText('Advanced_settings'));

const broadcast = screen.getByLabelText('Teams_New_Broadcast_Label') as HTMLInputElement;
const priv = screen.getByLabelText('Teams_New_Private_Label') as HTMLInputElement;

// Private initially ON in this configuration
expect(priv).toBeChecked();
expect(broadcast).not.toBeChecked();

await userEvent.click(broadcast);
expect(broadcast).toBeChecked();
expect(priv).toBeChecked(); // Private unchanged

await userEvent.click(broadcast);
expect(broadcast).not.toBeChecked();
expect(priv).toBeChecked(); // Still unchanged
});

it('With set-readonly permission: Broadcast ON forces ReadOnly ON+disabled; OFF re-enables it and preserves state', async () => {
render(<CreateTeamModalComponent onClose={() => null} />, {
wrapper: mockAppRoot().withPermission('set-readonly').build(),
});

await userEvent.click(screen.getByText('Advanced_settings'));

const broadcast = screen.getByLabelText('Teams_New_Broadcast_Label') as HTMLInputElement;
const readOnly = screen.getByLabelText('Teams_New_Read_only_Label') as HTMLInputElement;

// With permission and Broadcast OFF, ReadOnly is user-controllable
expect(broadcast).not.toBeChecked();
expect(readOnly).toBeEnabled();
expect(readOnly).not.toBeChecked();

// User can enable ReadOnly
await userEvent.click(readOnly);
expect(readOnly).toBeChecked();

// Turning Broadcast ON forces ReadOnly ON and disables it
await userEvent.click(broadcast);
expect(broadcast).toBeChecked();
expect(readOnly).toBeChecked();
expect(readOnly).toBeDisabled();

// Turning Broadcast OFF re-enables ReadOnly and preserves ON state
await userEvent.click(broadcast);
expect(broadcast).not.toBeChecked();
expect(readOnly).toBeChecked();
expect(readOnly).toBeEnabled();

// User can then toggle ReadOnly OFF again
await userEvent.click(readOnly);
expect(readOnly).not.toBeChecked();
});

it('E2E disabled: Encrypted remains OFF and disabled regardless of Private state', async () => {
render(<CreateTeamModalComponent onClose={() => null} />, {
wrapper: mockAppRoot().withSetting('E2E_Enable', false).withSetting('E2E_Enabled_Default_PrivateRooms', true).build(),
});

await userEvent.click(screen.getByText('Advanced_settings'));

const encrypted = screen.getByLabelText('Teams_New_Encrypted_Label') as HTMLInputElement;
const priv = screen.getByLabelText('Teams_New_Private_Label') as HTMLInputElement;

// Initially OFF + disabled
expect(encrypted).not.toBeChecked();
expect(encrypted).toBeDisabled();

// Toggle Private OFF -> still OFF + disabled
await userEvent.click(priv);
expect(priv).not.toBeChecked();
expect(encrypted).not.toBeChecked();
expect(encrypted).toBeDisabled();

// Toggle Private ON again -> still OFF + disabled because E2E is disabled globally
await userEvent.click(priv);
expect(priv).toBeChecked();
expect(encrypted).not.toBeChecked();
expect(encrypted).toBeDisabled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,84 @@ describe.each([
});
});
});

describe.each([
['useEncryptedRoomDescription in NavBarV2', useEncryptedRoomDescription],
['useEncryptedRoomDescription', useEncryptedRoomDescriptionOld],
] as const)('%s - extended', (_name, useEncryptedRoomDescriptionHook: Hook) => {
const wrapper = mockAppRoot();

beforeEach(() => {
jest.clearAllMocks();
});

describe.each(['channel', 'team'] as const)('roomType=%s (extended)', (roomType) => {
it('returns "Encrypted_not_available" when E2E enabled but room is public (encrypted=true)', () => {
const { result } = renderHook(() => useEncryptedRoomDescriptionHook(roomType), {
wrapper: wrapper.withSetting('E2E_Enable', true).build(),
});
const describe = result.current;

expect(describe({ isPrivate: false, encrypted: true })).toBe('Encrypted_not_available');
});

it('returns "Not_available_for_this_workspace" for E2E disabled regardless of room privacy/encryption', () => {
const { result } = renderHook(() => useEncryptedRoomDescriptionHook(roomType), {
wrapper: wrapper.withSetting('E2E_Enable', false).build(),
});
const describe = result.current;

expect(describe({ isPrivate: true, encrypted: true })).toBe('Not_available_for_this_workspace');
expect(describe({ isPrivate: true, encrypted: false })).toBe('Not_available_for_this_workspace');
expect(describe({ isPrivate: false, encrypted: true })).toBe('Not_available_for_this_workspace');
expect(describe({ isPrivate: false, encrypted: false })).toBe('Not_available_for_this_workspace');
});

it('returns a function descriptor and maintains referential stability across identical wrapper states', () => {
const makeWrapper = () => wrapper.withSetting('E2E_Enable', true).build();

const { result: r1 } = renderHook(() => useEncryptedRoomDescriptionHook(roomType), { wrapper: makeWrapper() });
const fn1 = r1.current;
expect(typeof fn1).toBe('function');
// Re-render with same settings; hook should deliver a function reference (may or may not be stable by design).
// This assertion is intentionally weak to avoid over-constraining implementation; we only ensure a function is returned.
const { result: r2 } = renderHook(() => useEncryptedRoomDescriptionHook(roomType), { wrapper: makeWrapper() });
const fn2 = r2.current;
expect(typeof fn2).toBe('function');

// Sanity check both functions behave equivalently under the same inputs.
const input = { isPrivate: true, encrypted: true as const };
expect(fn1(input)).toBe('Encrypted_messages');
expect(fn2(input)).toBe('Encrypted_messages');
});

it('handles unexpected input values gracefully by treating non-boolean truthy/falsy as booleans', () => {
const { result } = renderHook(() => useEncryptedRoomDescriptionHook(roomType), {
wrapper: wrapper.withSetting('E2E_Enable', true).build(),
});
const describe = result.current as any;

// isPrivate truthy (1), encrypted falsy (0) -> expect "Encrypted_messages_false"
expect(describe({ isPrivate: 1, encrypted: 0 })).toBe('Encrypted_messages_false');

// isPrivate falsy (''), encrypted truthy ('yes') -> public room should remain "Encrypted_not_available"
expect(describe({ isPrivate: '', encrypted: 'yes' })).toBe('Encrypted_not_available');
});

it('prefers encryption=true description only when room is private and E2E is enabled', () => {
const { result } = renderHook(() => useEncryptedRoomDescriptionHook(roomType), {
wrapper: wrapper.withSetting('E2E_Enable', true).build(),
});
const describe = result.current;

// private + encrypted -> Encrypted_messages
expect(describe({ isPrivate: true, encrypted: true })).toBe('Encrypted_messages');

// private + not encrypted -> Encrypted_messages_false
expect(describe({ isPrivate: true, encrypted: false })).toBe('Encrypted_messages_false');

// public + encrypted -> still not available
expect(describe({ isPrivate: false, encrypted: true })).toBe('Encrypted_not_available');
});
});
});
Loading
Loading