import Profile from 'firefox-profile'
import { promisify } from 'node:util'
import type { Capabilities } from '@wdio/types'
import type { FirefoxProfileOptions } from './types.js'
export default class FirefoxProfileLauncher {
private _profile?: Profile
constructor(private _options: FirefoxProfileOptions) {}
async onPrepare(config: never, capabilities: Capabilities.TestrunnerCapabilities) {
* Return if no profile options were specified
*/
if (Object.keys(this._options).length === 0) {
return
}
this._profile = this._options.profileDirectory
? await promisify(Profile.copy)(this._options.profileDirectory)
: new Profile()
if (!this._profile) {
return
}
this._setPreferences()
if (!Array.isArray(this._options.extensions)) {
return this._buildExtension(capabilities)
}
await promisify(this._profile.addExtensions.bind(this._profile))(this._options.extensions)
return this._buildExtension(capabilities)
}
* Sets any preferences and proxy
*/
_setPreferences() {
if (!this._profile) {
return
}
for (const [preference, value] of Object.entries(this._options)) {
if (['extensions', 'proxy', 'legacy', 'profileDirectory'].includes(preference)) {
continue
}
this._profile.setPreference(preference, value as string)
}
if (this._options.proxy) {
this._profile.setProxy(this._options.proxy)
}
this._profile.updatePreferences()
}
async _buildExtension(capabilities: Capabilities.TestrunnerCapabilities) {
if (!this._profile) {
return
}
const zippedProfile = await promisify(this._profile.encoded.bind(this._profile))()
if (Array.isArray(capabilities)) {
(capabilities as Capabilities.RequestedStandaloneCapabilities[] | Capabilities.RequestedMultiremoteCapabilities[])
.flatMap((c: Capabilities.RequestedStandaloneCapabilities | Capabilities.RequestedMultiremoteCapabilities) => {
if (Object.values(c).length > 0 && Object.values(c).every(c => typeof c === 'object' && c.capabilities)) {
return Object.values(c).map((o) => o.capabilities)
}
return c
})
.filter((capability) => capability.browserName === 'firefox')
.forEach((capability) => {
this._setProfile(capability, zippedProfile)
})
return
}
for (const browser in capabilities) {
const capability = capabilities[browser].capabilities as Capabilities.RequestedMultiremoteCapabilities[string]['capabilities']
const cap = capability && ('alwaysMatch' in capability ? capability.alwaysMatch : capability)
if (!capability || cap.browserName !== 'firefox') {
continue
}
this._setProfile(capability, zippedProfile)
}
}
_setProfile(capability: Capabilities.RequestedStandaloneCapabilities, zippedProfile: string) {
const cap = 'alwaysMatch' in capability ? capability.alwaysMatch : capability
cap['moz:firefoxOptions'] = cap['moz:firefoxOptions'] || {}
cap['moz:firefoxOptions'].profile = zippedProfile
}
}