Skip to content

Commit ece7f94

Browse files
committed
Add qss private channels e2e tests
1 parent a2cbae9 commit ece7f94

10 files changed

Lines changed: 717 additions & 11 deletions

File tree

.github/workflows/e2e-linux.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ jobs:
8787
timeout_minutes: 25
8888
max_attempts: 3
8989
command: cd packages/e2e-tests && npm run test multipleClients.test.ts
90+
91+
- name: Run multiple clients test (private channels)
92+
uses: nick-fields/retry@14672906e672a08bd6eeb15720e9ed3ce869cdd4 # v2.9.0
93+
with:
94+
timeout_minutes: 25
95+
max_attempts: 3
96+
command: cd packages/e2e-tests && npm run test multipleClients.privateChannels.test.ts
9097

9198
- name: Run invitation link test - Includes 2 separate application clients
9299
uses: nick-fields/retry@14672906e672a08bd6eeb15720e9ed3ce869cdd4 # v2.9.0

.github/workflows/e2e-qss-linux.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ jobs:
8080
max_attempts: 3
8181
command: cd packages/e2e-tests && npm run test multipleClients.qss.test.ts
8282

83+
- name: Run multiple clients with QSS test (private channels)
84+
uses: nick-fields/retry@14672906e672a08bd6eeb15720e9ed3ce869cdd4 # v2.9.0
85+
with:
86+
timeout_minutes: 25
87+
max_attempts: 3
88+
command: cd packages/e2e-tests && npm run test multipleClients.privateChannels.qss.test.ts
89+
8390
- name: Run one client with QSS test
8491
uses: nick-fields/retry@14672906e672a08bd6eeb15720e9ed3ce869cdd4 # v2.9.0
8592
with:
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export class NotAMemberError extends Error {
2-
constructor() {
3-
super('Not a member of this channel')
2+
constructor(id?: string) {
3+
super(`Not a member of this channel: ${id}`)
44
}
55
}

packages/backend/src/nest/storage/channels/channels.service.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ export class ChannelsService extends EventEmitter {
209209
!chain.roles.amIMemberOfRole(payload.encrypted.scope.name)
210210
) {
211211
this.logger.warn(`Not a member of this channel, skipping channel entry decrypt`)
212-
throw new NotAMemberError()
212+
throw new NotAMemberError(id)
213213
}
214214

215215
try {
@@ -244,7 +244,7 @@ export class ChannelsService extends EventEmitter {
244244
}
245245
}
246246
} catch (err) {
247-
if (err instanceof NotAMemberError || err.message === 'Not a member of this channel') {
247+
if (err instanceof NotAMemberError || err.message.startsWith('Not a member of this channel')) {
248248
this.logger.warn(`Failed to decrypt and validate private channel entry, ignoring...`)
249249
return false
250250
}
@@ -300,6 +300,7 @@ export class ChannelsService extends EventEmitter {
300300
* @throws Error
301301
*/
302302
public async getChannel(id: string): Promise<Channel | undefined> {
303+
this.logger.debug('Getting channel', id)
303304
if (!this.channels) {
304305
throw new Error('Channels have not been initialized!')
305306
}
@@ -308,7 +309,15 @@ export class ChannelsService extends EventEmitter {
308309
return undefined
309310
}
310311
// need to rehydrate the UInt8Array bc json value encoding in KeyValueIndexedValidated does not maintain type
311-
return this.decryptChannelEntry(channelEncrypted as EncryptedAndSignedPayload, id)
312+
try {
313+
return this.decryptChannelEntry(channelEncrypted as EncryptedAndSignedPayload, id)
314+
} catch (e) {
315+
if (e instanceof NotAMemberError || e.message.startsWith('Not a member of this channel')) {
316+
this.logger.warn(`Failed to decrypt and validate private channel entry during getChannel, ignoring...`, id)
317+
} else {
318+
this.logger.error('Failed to decrypt channel entry', e)
319+
}
320+
}
312321
}
313322

314323
/**
@@ -318,14 +327,24 @@ export class ChannelsService extends EventEmitter {
318327
* @throws Error
319328
*/
320329
public async getChannels(): Promise<Channel[]> {
330+
this.logger.debug('Getting channels')
321331
if (!this.channels) {
322332
throw new Error('Channels have not been initialized!')
323333
}
324334
return (await this.channels.all())
325335
.map(x => {
326336
try {
337+
this.logger.debug('Decrypting channel entry', x.key)
327338
return this.decryptChannelEntry(x.value, x.key)
328339
} catch (e) {
340+
if (e instanceof NotAMemberError || e.message.startsWith('Not a member of this channel')) {
341+
this.logger.warn(
342+
`Failed to decrypt and validate private channel entry during getChannels, ignoring...`,
343+
x.key
344+
)
345+
} else {
346+
this.logger.error('Failed to decrypt channel entry', e)
347+
}
329348
return undefined
330349
}
331350
})

packages/desktop/src/renderer/components/Channel/AddMembersChannel/AddMembersChannelComponent.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,14 @@ export const AddMembersChannelComponent: React.FC<ReturnType<typeof useModal> &
305305
direction='row'
306306
justifyContent='center'
307307
>
308-
<Button variant='contained' onClick={handleClose} size='small' fullWidth className={classes.secondaryButton}>
308+
<Button
309+
variant='contained'
310+
onClick={handleClose}
311+
size='small'
312+
fullWidth
313+
className={classes.secondaryButton}
314+
data-testid={`${channelName}-add-members-leave-button`}
315+
>
309316
Never mind
310317
</Button>
311318
</Grid>

packages/desktop/src/renderer/components/LoadingPanel/LoadingPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const LoadingPanel = () => {
4848
logger.info('Joining completed')
4949
loadingPanelModal.handleClose()
5050
}
51-
}, [isJoiningCompletedSelector])
51+
}, [isJoiningCompletedSelector, areMessages, areChannels, isCurrentCommunityInitialized])
5252

5353
useEffect(() => {
5454
if (isConnected) {

packages/e2e-tests/src/selectors.ts

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,74 @@ export class ChannelContextMenu {
733733
500
734734
)
735735
await button.click()
736+
await sleep(5_000)
737+
}
738+
739+
async checkForMembersInAddMembersAutocomplete(channelName: string, memberNames: string[]): Promise<string[]> {
740+
const autoCompleteInput = await this.driver.wait(
741+
until.elementLocated(By.xpath(`//div[@data-testid="${channelName}-add-members-autocomplete"]`)),
742+
20_000,
743+
`Channel add members autocomplete input div couldn't be located within timeout`,
744+
500
745+
)
746+
await this.driver.wait(
747+
until.elementIsVisible(autoCompleteInput),
748+
15_000,
749+
`Channel context menu channel add members autocomplete div was not visibile within timeout`,
750+
500
751+
)
752+
753+
const inputField = await this.driver.wait(
754+
autoCompleteInput.findElement(By.xpath(`//input[@aria-autocomplete="list"]`)),
755+
5_000,
756+
`Channel add members autocomplete input field couldn't be located within timeout`,
757+
500
758+
)
759+
760+
const waitForUserInAutocomplete = async (memberName: string) => {
761+
const autoCompleteOption = await this.driver.wait(
762+
until.elementLocated(
763+
By.xpath(`//div[@data-testid="${channelName}-add-members-autocomplete-option-${memberName}"]`)
764+
),
765+
2_000,
766+
`Channel add members autocomplete option for ${memberName} couldn't be located within timeout`,
767+
500
768+
)
769+
await this.driver.wait(
770+
until.elementIsVisible(autoCompleteOption),
771+
2_000,
772+
`Channel add members autocomplete option for ${memberName} wasn't visible within timeout`,
773+
500
774+
)
775+
}
776+
777+
const membersInAutocomplete: string[] = []
778+
for (const memberName of memberNames) {
779+
await inputField.sendKeys(memberName)
780+
try {
781+
await waitForUserInAutocomplete(memberName)
782+
membersInAutocomplete.push(memberName)
783+
} catch {
784+
// do nothing
785+
}
786+
await inputField.clear()
787+
}
788+
789+
const button = this.driver.wait(
790+
until.elementLocated(By.xpath(`//button[@data-testid="${channelName}-add-members-leave-button"]`)),
791+
20_000,
792+
`Channel add members leave button couldn't be located within timeout`,
793+
500
794+
)
795+
await this.driver.wait(
796+
until.elementIsVisible(button),
797+
15_000,
798+
`Channel add members leave button wasn't visibile within timeout`,
799+
500
800+
)
801+
await button.click()
736802
await sleep(5000)
803+
return membersInAutocomplete
737804
}
738805
}
739806

@@ -2029,19 +2096,22 @@ export class Sidebar {
20292096
return Promise.all(
20302097
elements.map(async element => {
20312098
const fullName = await element.getText()
2032-
return fullName.split(' ')[1]
2099+
if (fullName.startsWith('# ')) {
2100+
return fullName.split(' ')[1]
2101+
}
2102+
return fullName
20332103
})
20342104
)
20352105
}
20362106

2037-
async waitForChannelsNum(num: number) {
2107+
async waitForChannelsNum(num: number, timeoutMs: number = 15_000) {
20382108
logger.info(`Waiting for ${num} channels`)
20392109
return this.driver.wait(
20402110
async () => {
20412111
const channels = await this.getChannelList()
20422112
return channels.length === num
20432113
},
2044-
15_000,
2114+
timeoutMs,
20452115
`Sidebar channel list length couldn't be determined within timeout`,
20462116
500
20472117
)

0 commit comments

Comments
 (0)