Skip to content

Commit aeb0f41

Browse files
findmsgithub-actions[bot]netbe
authored
chore: test - Create channel conversation with Drive enabled - WPB-23810 (#4455)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: François Benaiteau <netbe@users.noreply.github.com>
1 parent 6071987 commit aeb0f41

File tree

16 files changed

+276
-36
lines changed

16 files changed

+276
-36
lines changed

WireMessaging/Sources/WireMessagingUI/ConversationCreation/ChannelCreationForm/ConversationChannelCreationFormView.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
public import SwiftUI
2020

2121
import WireDesign
22+
import WireLocators
2223
import WireMessagingDomain
2324
import WireReusableUIComponents
2425

@@ -96,6 +97,7 @@ public struct ConversationChannelCreationForm: View {
9697
Text(Strings.CreationForm.ChannelName.label)
9798
}
9899
)
100+
.accessibilityIdentifier(Locators.CreateChannelPage.channelNameField.rawValue)
99101
}
100102
}
101103

@@ -210,6 +212,7 @@ public struct ConversationChannelCreationForm: View {
210212
var fileManagementSection: some View {
211213
Section(content: {
212214
Toggle(Strings.CreationForm.WireCells.toggle, isOn: $viewModel.fileManagementEnabled)
215+
.accessibilityIdentifier(Locators.CreateChannelPage.sharedDriveSwitch.rawValue)
213216
}, footer: {
214217
Text(footerText)
215218
})

WireMessaging/Sources/WireMessagingUI/ConversationTypePicker.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ package struct ConversationTypePicker: View {
115115
chevronView()
116116
}
117117
})
118+
.accessibilityIdentifier(Locators.NewConversationPage.createNewChannelButton.rawValue)
118119
}
119120

120121
func groupItem() -> some View {

WireUI/Sources/WireLocators/Locators.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,13 @@ public enum Locators {
174174
case sharedDriveSwitch
175175
}
176176

177+
public enum CreateChannelPage: String {
178+
179+
case channelNameField
180+
case newChannelNextButton
181+
case sharedDriveSwitch
182+
}
183+
177184
public enum CreatePersonalAccountFormPage: String {
178185

179186
case enterNameField
@@ -197,6 +204,7 @@ public enum Locators {
197204
case cancelUserSearch = "Cancel"
198205
case cancel
199206
case usernameCell
207+
case createNewChannelButton
200208
}
201209

202210
public enum OnMyiPhonePage: String {

wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Create/WireConversationChannelCreationFormViewController.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import SwiftUI
2020
import WireDesign
2121
import WireDomain
22+
import WireLocators
2223
import WireLogging
2324
import WireMessagingDomain
2425
import WireMessagingUI
@@ -123,7 +124,7 @@ final class WireConversationChannelCreationFormViewController: UIViewController
123124
attemptToProceedToParticipants()
124125
}
125126
)
126-
nextButton.accessibilityIdentifier = "button.newchannel.next"
127+
nextButton.accessibilityIdentifier = Locators.CreateChannelPage.newChannelNextButton.rawValue
127128
navigationItem.rightBarButtonItem = nextButton
128129
nextButton.isEnabled = viewModel.isFormValid
129130
}

wire-ios/WireUITests/BackupRestoreHistoryTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ final class BackupRestoreHistoryTests: WireUITestCase {
2323

2424
@MainActor
2525
func testCreateBackupAndRestoreHistory_TC_8928_TC_8930_TC_8805() async throws {
26-
let groupName = UserGenerator.generateRandomGroupName()
26+
let groupName = UserGenerator.generateRandomConversationName()
2727
let messageFromOwner = UserGenerator.generateRandomMessage()
2828
let (_, teamOwner) = try await userHelper.registerUserAsTeamOwner()
2929
let ownerAccessToken = try await userHelper.fetchAccessToken(

wire-ios/WireUITests/Helper/BackOffice.swift

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,79 @@ final class BackOffice {
249249
}
250250
}
251251

252+
func unlockChannelFeature(teamId: String, basicAuth: String) async throws {
253+
254+
let trimmed = basicAuth.trimmingCharacters(in: .whitespacesAndNewlines)
255+
256+
let headerValue: String = if trimmed.lowercased().hasPrefix("basic ") {
257+
trimmed
258+
} else {
259+
"Basic \(trimmed)"
260+
}
261+
262+
let endpoint = backendURL
263+
.appendingPathComponent("i")
264+
.appendingPathComponent("teams")
265+
.appendingPathComponent(teamId)
266+
.appendingPathComponent("features")
267+
.appendingPathComponent("channels")
268+
.appendingPathComponent("unlocked")
269+
270+
let (data, code) = try await sendRequest(
271+
endpoint: endpoint,
272+
method: .put,
273+
body: Data("{}".utf8),
274+
basicAuth: headerValue
275+
)
276+
277+
guard code.statusCode == 200 else {
278+
throw RuntimeError(
279+
"unlockCellsFeature failed: HTTP \(code.statusCode) \(String(data: data, encoding: .utf8) ?? "")"
280+
)
281+
}
282+
}
283+
284+
func enableChannelFeature(teamId: String, basicAuth: String) async throws {
285+
286+
let trimmed = basicAuth.trimmingCharacters(in: .whitespacesAndNewlines)
287+
288+
let headerValue: String = if trimmed.lowercased().hasPrefix("basic ") {
289+
trimmed
290+
} else {
291+
"Basic \(trimmed)"
292+
}
293+
294+
let endpoint = backendURL
295+
.appendingPathComponent("i")
296+
.appendingPathComponent("teams")
297+
.appendingPathComponent(teamId)
298+
.appendingPathComponent("features")
299+
.appendingPathComponent("channels")
300+
301+
let payload: [String: Any] = [
302+
"config": [
303+
"allowed_to_create_channels": "team-members",
304+
"allowed_to_open_channels": "team-members"
305+
],
306+
"status": "enabled",
307+
"ttl": "unlimited"
308+
]
309+
310+
let json = try JSONSerialization.data(withJSONObject: payload, options: [])
311+
let (data, code) = try await sendRequest(
312+
endpoint: endpoint,
313+
method: .put,
314+
body: json,
315+
basicAuth: headerValue
316+
)
317+
318+
guard code.statusCode == 200 else {
319+
throw RuntimeError(
320+
"enableCellsBackdoorViaBackendTeam failed: HTTP \(code.statusCode) \(String(data: data, encoding: .utf8) ?? "")"
321+
)
322+
}
323+
}
324+
252325
// MARK: - models - Cells Feature
253326

254327
private struct CellsFeaturePayload: Codable {

wire-ios/WireUITests/Helper/UserGenerator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ enum UserGenerator {
6161
return String(character)
6262
}
6363

64-
static func generateRandomGroupName() -> String {
64+
static func generateRandomConversationName() -> String {
6565
let timestamp = Int(Date().timeIntervalSince1970) % 100_000
6666
let hex = String(format: "%03x", Int.random(in: 0 ... 0xFFF))
67-
return "Group_\(timestamp)\(hex)"
67+
return "Conversation_\(timestamp)\(hex)"
6868
}
6969

7070
static func generateRandomMessage() -> String {

wire-ios/WireUITests/Helper/UserHelper.swift

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,42 @@ class UserHelper {
450450
_ = try await conversationsAPI.createGroupConversation(parameters: params)
451451
}
452452

453+
/// Create channel conversation
454+
/// - Parameters:
455+
/// - qualifiedIds: qualifiedIds for members of the channel
456+
/// - owner: group owner
457+
/// - groupName: groupName
458+
func createChannelConversations(
459+
qualifiedIds: [QualifiedID],
460+
owner: UserInfo,
461+
channelName: String
462+
) async throws {
463+
464+
let params = CreateGroupConversationParameters(
465+
groupType: .channel,
466+
messageProtocol: .mls,
467+
creatorClientID: "deprecated",
468+
qualifiedUserIDs: qualifiedIds,
469+
unqualifiedUserIDs: [],
470+
name: channelName,
471+
accessMode: [.invite, .code],
472+
accessRoles: [.teamMember, .guest, .app, .nonTeamMember],
473+
legacyAccessRole: nil,
474+
teamID: owner.teamID,
475+
isReadReceiptsEnabled: true
476+
)
477+
478+
let (_, accessToken) = try await authenticationAPI.login(
479+
email: owner.email,
480+
password: owner.password,
481+
verificationCode: nil,
482+
label: nil
483+
)
484+
authenticationManager.accessToken = accessToken
485+
486+
_ = try await conversationsAPI.createGroupConversation(parameters: params)
487+
}
488+
453489
/// Registers a set of teams for a specific owner.
454490
///
455491
/// - Parameter teamOwner: The user information of the person who will own the teams.
@@ -476,14 +512,14 @@ class UserHelper {
476512
return [teamMember1.name, teamMember2.name]
477513
}
478514

479-
/// Registers a team with a given number of members and add them to a group
515+
/// Registers a team with a given number of members and optionally creates a group or channel conversation
480516
/// - Parameters:
481517
/// - memberCount: count of members
482-
/// - groupName : optional groupName
483-
/// - Returns: teamOwner info, teamMembers info, qualifiedIds of members, conversationId if group created
518+
/// - conversation: optional group or channel conversation to create
519+
/// - Returns: teamOwner info, teamMembers info, qualifiedIds of members, conversationId if conversation created
484520
func registerTeam(
485521
withMemberCount memberCount: Int,
486-
groupName: String? = nil
522+
conversation: CreateConversationOption? = nil
487523
) async throws
488524
-> (teamOwner: UserInfo, teamMembers: [UserInfo], qualifiedIDs: [QualifiedID], conversationId: UUID?) {
489525

@@ -512,17 +548,36 @@ class UserHelper {
512548
teamMembers.append(teamMember)
513549
}
514550

515-
// if group conversation passed
551+
// if conversation creation is requested
516552
var conversationId: UUID?
517-
if let groupName {
518-
try await createGroupConversations(
519-
qualifiedIds: qualifiedIDs,
520-
owner: teamOwner,
521-
groupName: groupName
522-
)
523-
524-
let (resolvedConversationId, _) = try await getConversationId(matching: .groupName(groupName))
525-
conversationId = resolvedConversationId
553+
if let conversation {
554+
switch conversation {
555+
case let .group(name):
556+
try await createGroupConversations(
557+
qualifiedIds: qualifiedIDs,
558+
owner: teamOwner,
559+
groupName: name
560+
)
561+
562+
let (resolvedConversationId, _) = try await getConversationId(matching: .groupName(name))
563+
conversationId = resolvedConversationId
564+
565+
case let .channel(name):
566+
// unlock and enable Channels
567+
let backOffice = BackOffice(backendURL: backendURL)
568+
let basicAuth = basicAuth()
569+
try await backOffice.unlockChannelFeature(teamId: teamID.uuidString, basicAuth: basicAuth)
570+
try await backOffice.enableChannelFeature(teamId: teamID.uuidString, basicAuth: basicAuth)
571+
572+
try await createChannelConversations(
573+
qualifiedIds: qualifiedIDs,
574+
owner: teamOwner,
575+
channelName: name
576+
)
577+
578+
let (resolvedConversationId, _) = try await getConversationId(matching: .groupName(name))
579+
conversationId = resolvedConversationId
580+
}
526581
}
527582

528583
// unlock and enable ConferenceCalling
@@ -584,6 +639,15 @@ class UserHelper {
584639
try await backOffice.unlockCellsFeature(teamId: teamID.uuidString, basicAuth: basicAuth)
585640
try await backOffice.enableCellsFeature(teamId: teamID.uuidString, basicAuth: basicAuth)
586641
}
642+
643+
/// Unlock and Enable Channel feature
644+
/// - Parameter teamID: teamID where this needs to be enabled
645+
func unlockAndEnableChannelFeature(teamID: UUID) async throws {
646+
let backOffice = BackOffice(backendURL: backendURL)
647+
let basicAuth = basicAuth()
648+
try await backOffice.unlockChannelFeature(teamId: teamID.uuidString, basicAuth: basicAuth)
649+
try await backOffice.enableChannelFeature(teamId: teamID.uuidString, basicAuth: basicAuth)
650+
}
587651
}
588652

589653
extension BackendEnvironment {
@@ -616,6 +680,11 @@ extension BackendEnvironment {
616680
)
617681
}
618682

683+
enum CreateConversationOption {
684+
case group(String)
685+
case channel(String)
686+
}
687+
619688
enum FilterConversationsByCriteria {
620689
case groupName(String)
621690
case conversationType(ConversationType?)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// Wire
3+
// Copyright (C) 2026 Wire Swiss GmbH
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU General Public License
16+
// along with this program. If not, see http://www.gnu.org/licenses/.
17+
//
18+
19+
import WireLocators
20+
import XCTest
21+
22+
class CreateChannelPage: PageModel {
23+
24+
override var pageMainElement: XCUIElement {
25+
channelNameTextfield
26+
}
27+
28+
var channelNameTextfield: XCUIElement {
29+
app.descendants(matching: .any)[Locators.CreateChannelPage.channelNameField.rawValue].firstMatch
30+
}
31+
32+
var nextButton: XCUIElement {
33+
app.descendants(matching: .any)[Locators.CreateChannelPage.newChannelNextButton.rawValue].firstMatch
34+
}
35+
36+
var shareDriveSwitch: XCUIElement {
37+
app.descendants(matching: .any)[Locators.CreateChannelPage.sharedDriveSwitch.rawValue].switches.firstMatch
38+
}
39+
40+
func enableShareDriveSwitch() throws -> CreateChannelPage {
41+
shareDriveSwitch.tap()
42+
return self
43+
}
44+
45+
func enterChannelName(_ channelName: String) throws -> SelectParticipantsPage {
46+
try channelNameTextfield.tapIfKeyboardNotFocused().typeText(channelName)
47+
nextButton.tap()
48+
return try SelectParticipantsPage()
49+
}
50+
}

wire-ios/WireUITests/Pages/NewConversationPage.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,20 @@ class NewConversationPage: PageModel {
2929
app.descendants(matching: .any)[Locators.NewConversationPage.createNewGroupButton.rawValue].firstMatch
3030
}
3131

32+
var newChannelButton: XCUIElement {
33+
app.descendants(matching: .any)[Locators.NewConversationPage.createNewChannelButton.rawValue].firstMatch
34+
}
35+
3236
func tapNewGroupButton() throws -> CreateGroupPage {
3337
newGroupButton.tap()
3438
return try CreateGroupPage()
3539
}
3640

41+
func tapNewChannelButton() throws -> CreateChannelPage {
42+
newChannelButton.tap()
43+
return try CreateChannelPage()
44+
}
45+
3746
var searchByNameOrUsernameSearchBox: XCUIElement {
3847
app.descendants(matching: .any)[Locators.NewConversationPage.searchByNameOrUsername.rawValue].firstMatch
3948
}

0 commit comments

Comments
 (0)