-
Notifications
You must be signed in to change notification settings - Fork 341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Can't run with specified profile name and --keep-profile-changes #968
Changes from 12 commits
e7712a0
0af91f6
9b7ce5a
939a2a3
2be9919
806f9e0
854b09c
5876d14
9fc5e9d
8c333de
c09b22e
1709154
ac9a6b2
232e1e5
fdff679
bfb1703
4c4d407
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -99,6 +99,11 @@ export interface FirefoxProcess extends events$EventEmitter { | |||
kill: Function; | ||||
} | ||||
|
||||
export interface IProfileFinder { | ||||
hasProfileName(): Promise<boolean>; | ||||
getPath(): Promise<string>; | ||||
} | ||||
|
||||
export type FirefoxRunnerResults = {| | ||||
process: FirefoxProcess, | ||||
binary: string, | ||||
|
@@ -239,8 +244,34 @@ export type UseProfileParams = { | |||
app?: PreferencesAppName, | ||||
configureThisProfile?: ConfigureProfileFn, | ||||
customPrefs?: FirefoxPreferences, | ||||
createProfileFinder?: typeof defaultCreateProfileFinder, | ||||
}; | ||||
|
||||
export function defaultCreateProfileFinder() { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the new tests are using a fake To make this function more easily testable we should add an optional There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what tests do you propose ? |
||||
const finder = new FirefoxProfile.Finder(); | ||||
const readProfiles = promisify(finder.readProfiles, finder); | ||||
return { | ||||
getPath: promisify(finder.getPath, finder), | ||||
hasProfileName: async (profileName: string) => { | ||||
try { | ||||
await fs.stat(path.join(FirefoxProfile.Finder.locateUserDirectory(), | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @harikishen the tests are failing because on an issue in the
And so it should be something like: const profilesIniPath = path.join(
userDirectoryPath || FirefoxProfile.Finder.locateUserDirectory(),
'profiles.ini'
);
const res = await fs.stat(profilesIniPath); |
||||
'profile.ini')); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "profiles.ini" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually I was trying the case if the file did not exist... forgot to fix it |
||||
} catch (error) { | ||||
if (isErrorWithCode('ENOENT', error)) { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This try catch should only surround the |
||||
log.info('No firefox profiles exist'); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, we have already checked that "profiles.ini" doesn't exist (which should probably be a warning instead of an info message), but we are going to execute And so I think that it would be reasonable to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the call for warning...??? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unsurprisingly Line 174 in 97404a9
|
||||
} else { | ||||
throw error; | ||||
} | ||||
} | ||||
await readProfiles(); | ||||
return finder.profiles.filter( | ||||
(profileDef) => profileDef.Name === profileName | ||||
).length !== 0; | ||||
}, | ||||
}; | ||||
} | ||||
|
||||
|
||||
// Use the target path as a Firefox profile without cloning it | ||||
|
||||
export async function useProfile( | ||||
|
@@ -249,9 +280,44 @@ export async function useProfile( | |||
app, | ||||
configureThisProfile = configureProfile, | ||||
customPrefs = {}, | ||||
createProfileFinder = defaultCreateProfileFinder, | ||||
}: UseProfileParams = {}, | ||||
): Promise<FirefoxProfile> { | ||||
const profile = new FirefoxProfile({destinationDirectory: profilePath}); | ||||
let profile; | ||||
const finder = createProfileFinder(); | ||||
try { | ||||
const dirExists = await isDirectory(profilePath); | ||||
const defaultProfilePath = ( | ||||
finder.hasProfileName('default') && await finder.getPath('default') | ||||
); | ||||
const defaultDevProfilePath = ( | ||||
finder.hasProfileName('dev-edition-default') && | ||||
await finder.getPath('dev-edition-default') | ||||
); | ||||
if (dirExists) { | ||||
log.debug(`Using profile directory from "${profilePath}"`); | ||||
if (profilePath === defaultProfilePath || | ||||
profilePath === defaultDevProfilePath) { | ||||
throw new WebExtError( | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By looking at the coverage reports, this line doesn't seem to be currently executed by any of the current tests. |
||||
`Cannot use profile at "${profilePath}"` | ||||
); | ||||
} | ||||
profile = new FirefoxProfile({destinationDirectory: profilePath}); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can make this function to call |
||||
} else { | ||||
log.debug(`Assuming ${profilePath} is a named profile`); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering if we should make this to always fail if the requested profile name is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rpl what do you propose ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. something like: if (profilePath === 'default' || profilePath === 'dev-edition-default') {
throw new WebExtError(`Cannot use the blacklisted named profile "${profilePath}" `);
} |
||||
if (profilePath === 'default' || | ||||
profilePath === 'dev-edition-default') { | ||||
throw new WebExtError( | ||||
`Cannot use the blacklisted named profile "${profilePath}"` | ||||
); | ||||
} | ||||
const profileDirectory = await finder.getPath(profilePath); | ||||
profile = new FirefoxProfile({destinationDirectory: profileDirectory}); | ||||
} | ||||
} catch (error) { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that this giant |
||||
throw new WebExtError( | ||||
`Could not use Firefox profile from ${profilePath}: ${error}`); | ||||
} | ||||
return await configureThisProfile(profile, {app, customPrefs}); | ||||
} | ||||
|
||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -324,6 +324,149 @@ describe('firefox', () => { | |
} | ||
)); | ||
|
||
it('configures a named profile', () => withTempDir( | ||
(tmpDir) => { | ||
const configureProfile = | ||
sinon.spy((profile) => Promise.resolve(profile)); | ||
const app = 'fennec'; | ||
const profilePath = tmpDir.path(); | ||
const profileFinder = () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @harikishen You should do something like: const profileFinder = {
getPath: sinon.spy(...),
...
};
const createProfileFinder = () => profileFinder;
const profile = await firefox.useProfile(profilePath, {
...
configureThisProfile: configureProfile,
createProfileFinder: createProfileFinder,
});
assert.equal(configureProfile.called, true);
...
assert.equal(profileFinder.getPath.callCount, 2) |
||
return { | ||
getPath: sinon.spy((pathToProfile) => | ||
Promise.resolve(pathToProfile)), | ||
hasProfileName: () => Promise.resolve(true), | ||
}; | ||
}; | ||
const spy = sinon.spy(profileFinder, "getPath"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @harikishen this is probably a leftover, but it is making the CI to fail on the eslint checks and it never reaches the unit tests: |
||
return firefox.useProfile(profilePath, | ||
{ | ||
app: 'fennec', | ||
configureThisProfile: configureProfile, | ||
createProfileFinder: profileFinder, | ||
}) | ||
.then((profile) => { | ||
assert.equal(configureProfile.called, true); | ||
assert.equal(configureProfile.firstCall.args[0], profile); | ||
assert.equal(configureProfile.firstCall.args[1].app, app); | ||
// assert.equal(profileFinder.getPath.callCount, 2) | ||
}); | ||
} | ||
)); | ||
|
||
it('does not configure named profile default', () => { | ||
const configureProfile = | ||
sinon.spy((profile) => Promise.resolve(profile)); | ||
const profileFinder = () => { | ||
return { | ||
getPath: () => Promise.resolve(), | ||
hasProfileName: () => Promise.resolve(true), | ||
}; | ||
}; | ||
return firefox.useProfile('default', | ||
{ | ||
app: 'fennec', | ||
configureThisProfile: configureProfile, | ||
createProfileFinder: profileFinder, | ||
}) | ||
.then((profile) => { | ||
assert.equal(configureProfile.called, true); | ||
assert.equal(configureProfile.firstCall.args[0], profile); | ||
assert.equal(configureProfile.firstCall.args[1].app, 'fennec'); | ||
}) | ||
.catch((error) => { | ||
assert.instanceOf(error, WebExtError); | ||
assert.match(error.message, | ||
/Cannot use the blacklisted named profile "default"+/); | ||
}); | ||
}); | ||
|
||
it('does not configure named profile dev-edition-default', () => { | ||
const configureProfile = | ||
sinon.spy((profile) => Promise.resolve(profile)); | ||
const profileFinder = () => { | ||
return { | ||
getPath: () => Promise.resolve(), | ||
hasProfileName: () => Promise.resolve(true), | ||
}; | ||
}; | ||
return firefox.useProfile('dev-edition-default', | ||
{ | ||
app: 'fennec', | ||
configureThisProfile: configureProfile, | ||
createProfileFinder: profileFinder, | ||
}) | ||
.then((profile) => { | ||
assert.equal(configureProfile.called, true); | ||
assert.equal(configureProfile.firstCall.args[0], profile); | ||
assert.equal(configureProfile.firstCall.args[1].app, 'fennec'); | ||
}) | ||
.catch((error) => { | ||
assert.instanceOf(error, WebExtError); | ||
assert.match(error.message, | ||
/Cannot use the blacklisted named profile "dev-edition-default"+/); | ||
}); | ||
}); | ||
|
||
it('does not configure profile at default', () => withTempDir( | ||
(tmpDir) => { | ||
const configureProfile = | ||
sinon.spy((profile) => Promise.resolve(profile)); | ||
const defaultPath = path.join(tmpDir.path(), 'fake-profile.default'); | ||
const profileFinder = () => { | ||
return { | ||
getPath: (profilePath) => Promise.resolve(profilePath), | ||
hasProfileName: () => Promise.resolve(true), | ||
}; | ||
}; | ||
return firefox.useProfile(defaultPath, | ||
{ | ||
app: 'fennec', | ||
configureThisProfile: configureProfile, | ||
createProfileFinder: profileFinder, | ||
}) | ||
.then((profile) => { | ||
assert.equal(configureProfile.called, true); | ||
assert.equal(configureProfile.firstCall.args[0], profile); | ||
assert.equal(configureProfile.firstCall.args[1].app, 'fennec'); | ||
}) | ||
.catch((error) => { | ||
assert.instanceOf(error, WebExtError); | ||
assert.match(error.message, | ||
/Cannot use profile at+/); | ||
}); | ||
} | ||
)); | ||
|
||
it('does not configure profile at dev-edition-default', () => withTempDir( | ||
(tmpDir) => { | ||
const configureProfile = | ||
sinon.spy((profile) => Promise.resolve(profile)); | ||
const defaultDevPath = path.join(tmpDir.path(), | ||
'fake-profile.dev-edition-default'); | ||
const profileFinder = () => { | ||
return { | ||
getPath: (profilePath) => Promise.resolve(profilePath), | ||
hasProfileName: () => Promise.resolve(true), | ||
}; | ||
}; | ||
return firefox.useProfile(defaultDevPath, | ||
{ | ||
app: 'fennec', | ||
configureThisProfile: configureProfile, | ||
createProfileFinder: profileFinder, | ||
}) | ||
.then((profile) => { | ||
assert.equal(configureProfile.called, true); | ||
assert.equal(configureProfile.firstCall.args[0], profile); | ||
assert.equal(configureProfile.firstCall.args[1].app, 'fennec'); | ||
}) | ||
.catch((error) => { | ||
assert.instanceOf(error, WebExtError); | ||
assert.match(error.message, | ||
/Cannot use profile at+/); | ||
}); | ||
} | ||
)); | ||
}); | ||
|
||
describe('configureProfile', () => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This flow type is currently unused and it should be used for the
defaultCreateProfileFinder
return value type annotation (we should also move it near that function, that is where it is going to be used).Also, the type signatures are wrong: both
hasProfileName
andgetPath
take a string as parameter(and so they should be
hasProfileName(string): Promise<boolean>
, andgetPath
needs the same kind of fix).