diff --git a/packages/desktop-gui/cypress/integration/login_spec.js b/packages/desktop-gui/cypress/integration/login_spec.js
index 5a9ec1865502..82ce041e6c4a 100644
--- a/packages/desktop-gui/cypress/integration/login_spec.js
+++ b/packages/desktop-gui/cypress/integration/login_spec.js
@@ -69,6 +69,12 @@ describe('Login', function () {
})
})
+ it('passes utm code when it triggers ipc \'begin:auth\'', function () {
+ cy.then(function () {
+ expect(this.ipc.beginAuth).to.be.calledWith('Nav Login Button')
+ })
+ })
+
it('disables login button', () => {
cy.get('@loginBtn').should('be.disabled')
})
diff --git a/packages/desktop-gui/cypress/integration/runs_list_spec.js b/packages/desktop-gui/cypress/integration/runs_list_spec.js
index d62ee612b685..c47ceeade608 100644
--- a/packages/desktop-gui/cypress/integration/runs_list_spec.js
+++ b/packages/desktop-gui/cypress/integration/runs_list_spec.js
@@ -303,6 +303,18 @@ describe('Runs List', function () {
it('does not fetch runs', function () {
expect(this.ipc.getRuns).not.to.be.called
})
+
+ it('clicking Log In to Dashboard opens login', () => {
+ cy.contains('button', 'Log In to Dashboard').click().then(function () {
+ expect(this.ipc.beginAuth).to.be.calledOnce
+ })
+ })
+
+ it('clicking Log In to Dashboard passes utm code', () => {
+ cy.contains('button', 'Log In to Dashboard').click().then(function () {
+ expect(this.ipc.beginAuth).to.be.calledWith('Runs Tab Login Button')
+ })
+ })
})
context('without a project id', function () {
@@ -345,7 +357,7 @@ describe('Runs List', function () {
it('clicking Log In to Dashboard opens login', () => {
cy.contains('button', 'Log In to Dashboard').click().then(function () {
- expect(this.ipc.beginAuth).to.be.called
+ expect(this.ipc.beginAuth).to.be.calledOnce
})
})
})
diff --git a/packages/desktop-gui/src/auth/auth-api.js b/packages/desktop-gui/src/auth/auth-api.js
index 0da2a4fba17a..44e1e1f4be2e 100644
--- a/packages/desktop-gui/src/auth/auth-api.js
+++ b/packages/desktop-gui/src/auth/auth-api.js
@@ -21,12 +21,12 @@ class AuthApi {
})
}
- login () {
+ login (utm) {
ipc.onAuthMessage((__, message) => {
authStore.setMessage(message)
})
- return ipc.beginAuth()
+ return ipc.beginAuth(utm)
.then((user) => {
authStore.setUser(user)
authStore.setMessage(null)
diff --git a/packages/desktop-gui/src/auth/login-form.jsx b/packages/desktop-gui/src/auth/login-form.jsx
index d24ec89cb738..4d159f29084e 100644
--- a/packages/desktop-gui/src/auth/login-form.jsx
+++ b/packages/desktop-gui/src/auth/login-form.jsx
@@ -115,7 +115,7 @@ class LoginForm extends Component {
this.setState({ isLoggingIn: true })
- authApi.login()
+ authApi.login(this.props.utm)
.then(() => {
this.props.onSuccess()
})
diff --git a/packages/desktop-gui/src/auth/login-modal.jsx b/packages/desktop-gui/src/auth/login-modal.jsx
index 058fe388cb05..949213dd8639 100644
--- a/packages/desktop-gui/src/auth/login-modal.jsx
+++ b/packages/desktop-gui/src/auth/login-modal.jsx
@@ -70,7 +70,7 @@ class LoginContent extends Component {
x
Log In
Logging in gives you access to the Cypress Dashboard Service. You can set up projects to be recorded and see test data from your project.
- this.setState({ succeeded: true })} />
+ this.setState({ succeeded: true })} />
)
}
diff --git a/packages/desktop-gui/src/runs/runs-list.jsx b/packages/desktop-gui/src/runs/runs-list.jsx
index 2f8a0fb44c87..28633151f917 100644
--- a/packages/desktop-gui/src/runs/runs-list.jsx
+++ b/packages/desktop-gui/src/runs/runs-list.jsx
@@ -284,7 +284,7 @@ class RunsList extends Component {
-
+
)
}
diff --git a/packages/server/lib/gui/auth.js b/packages/server/lib/gui/auth.js
index 70aeaaca51e8..c66062b59327 100644
--- a/packages/server/lib/gui/auth.js
+++ b/packages/server/lib/gui/auth.js
@@ -19,6 +19,7 @@ let authState
let openExternalAttempted = false
let authRedirectReached = false
let server
+let utm
const _buildLoginRedirectUrl = (server) => {
const { port } = server.address()
@@ -26,7 +27,7 @@ const _buildLoginRedirectUrl = (server) => {
return `http://127.0.0.1:${port}/redirect-to-auth`
}
-const _buildFullLoginUrl = (baseLoginUrl, server) => {
+const _buildFullLoginUrl = (baseLoginUrl, server, utmCode) => {
const { port } = server.address()
if (!authState) {
@@ -45,6 +46,16 @@ const _buildFullLoginUrl = (baseLoginUrl, server) => {
platform: os.platform(),
}
+ if (utmCode) {
+ authUrl.query = {
+ utm_source: 'Test Runner',
+ utm_medium: 'Login Button',
+ utm_campaign: 'TR-Dashboard',
+ utm_content: utmCode,
+ ...authUrl.query,
+ }
+ }
+
return authUrl.format()
})
}
@@ -58,7 +69,7 @@ const _getOriginFromUrl = (originalUrl) => {
/**
* @returns a promise that is resolved with a user when auth is complete or rejected when it fails
*/
-const start = (onMessage) => {
+const start = (onMessage, utmCode) => {
function sendMessage (type, name, arg1) {
onMessage({
type,
@@ -68,6 +79,7 @@ const start = (onMessage) => {
})
}
+ utm = utmCode
authRedirectReached = false
return user.getBaseLoginUrl()
@@ -110,7 +122,7 @@ const _launchServer = (baseLoginUrl, sendMessage) => {
app.get('/redirect-to-auth', (req, res) => {
authRedirectReached = true
- _buildFullLoginUrl(baseLoginUrl, server)
+ _buildFullLoginUrl(baseLoginUrl, server, utm)
.then((fullLoginUrl) => {
debug('Received GET to /redirect-to-auth, redirecting: %o', { fullLoginUrl })
diff --git a/packages/server/lib/gui/events.js b/packages/server/lib/gui/events.js
index f58ff0ac9851..e120ead901b9 100644
--- a/packages/server/lib/gui/events.js
+++ b/packages/server/lib/gui/events.js
@@ -155,7 +155,7 @@ const handleEvent = function (options, bus, event, id, type, arg) {
return bus.emit('auth:message', msg)
}
- return auth.start(onMessage)
+ return auth.start(onMessage, arg)
.then(send)
.catch(sendErr)
diff --git a/packages/server/test/unit/gui/auth_spec.js b/packages/server/test/unit/gui/auth_spec.js
index 50ea9a93dda6..646b13b31b14 100644
--- a/packages/server/test/unit/gui/auth_spec.js
+++ b/packages/server/test/unit/gui/auth_spec.js
@@ -13,6 +13,7 @@ const RANDOM_STRING = 'a'.repeat(32)
const PORT = 9001
const REDIRECT_URL = `http://127.0.0.1:${PORT}/redirect-to-auth`
const FULL_LOGIN_URL = `https://foo.invalid/login.html?port=${PORT}&state=${RANDOM_STRING}&machineId=abc123&cypressVersion=${pkg.version}&platform=linux`
+const FULL_LOGIN_URL_UTM = `https://foo.invalid/login.html?utm_source=Test%20Runner&utm_medium=Login%20Button&utm_campaign=TR-Dashboard&utm_content=Login%20Button&port=${PORT}&state=${RANDOM_STRING}&machineId=abc123&cypressVersion=${pkg.version}&platform=linux`
describe('lib/gui/auth', function () {
beforeEach(() => {
@@ -66,6 +67,13 @@ describe('lib/gui/auth', function () {
expect(random.id).to.be.calledOnce
})
})
+
+ it('uses utm code to form a trackable URL', function () {
+ return auth._buildFullLoginUrl(BASE_URL, this.server, 'Login Button')
+ .then((url) => {
+ expect(url).to.eq(FULL_LOGIN_URL_UTM)
+ })
+ })
})
context('._launchNativeAuth', function () {