Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
Metabase
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Engineering Digital Service
Metabase
Commits
3e08a935
Commit
3e08a935
authored
7 years ago
by
Atte Keinänen
Browse files
Options
Downloads
Patches
Plain Diff
Fix issue with waitForAction, add documentation [ci e2e]
parent
c1978827
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
frontend/test/__support__/integrated_tests.js
+108
-93
108 additions, 93 deletions
frontend/test/__support__/integrated_tests.js
frontend/test/admin/settings/settings.integ.spec.js
+0
-1
0 additions, 1 deletion
frontend/test/admin/settings/settings.integ.spec.js
with
108 additions
and
94 deletions
frontend/test/__support__/integrated_tests.js
+
108
−
93
View file @
3e08a935
...
...
@@ -41,7 +41,6 @@ let loginSession = null; // Stores the current login session
let
previousLoginSession
=
null
;
let
simulateOfflineMode
=
false
;
/**
* Login to the Metabase test instance with default credentials
*/
...
...
@@ -66,6 +65,9 @@ export function logout() {
loginSession
=
null
}
/**
* Lets you recover the previous login session after calling logout
*/
export
function
restorePreviousLogin
()
{
if
(
previousLoginSession
)
{
loginSession
=
previousLoginSession
...
...
@@ -75,7 +77,7 @@ export function restorePreviousLogin() {
}
/**
* Calls the provided function while simulating that the browser is offline
.
* Calls the provided function while simulating that the browser is offline
*/
export
async
function
whenOffline
(
callWhenOffline
)
{
simulateOfflineMode
=
true
;
...
...
@@ -90,81 +92,14 @@ export async function whenOffline(callWhenOffline) {
});
}
// Patches the metabase/lib/api module so that all API queries contain the login credential cookie.
// Needed because we are not in a real web browser environment.
api
.
_makeRequest
=
async
(
method
,
url
,
headers
,
requestBody
,
data
,
options
)
=>
{
const
headersWithSessionCookie
=
{
...
headers
,
...(
loginSession
?
{
"
Cookie
"
:
`
${
METABASE_SESSION_COOKIE
}
=
${
loginSession
.
id
}
`
}
:
{})
}
const
fetchOptions
=
{
credentials
:
"
include
"
,
method
,
headers
:
new
Headers
(
headersWithSessionCookie
),
...(
requestBody
?
{
body
:
requestBody
}
:
{})
};
let
isCancelled
=
false
if
(
options
.
cancelled
)
{
options
.
cancelled
.
then
(()
=>
{
isCancelled
=
true
;
});
}
const
result
=
simulateOfflineMode
?
{
status
:
0
,
responseText
:
''
}
:
(
await
fetch
(
api
.
basename
+
url
,
fetchOptions
));
if
(
isCancelled
)
{
throw
{
status
:
0
,
data
:
''
,
isCancelled
:
true
}
}
let
resultBody
=
null
try
{
resultBody
=
await
result
.
text
();
// Even if the result conversion to JSON fails, we still return the original text
// This is 1-to-1 with the real _makeRequest implementation
resultBody
=
JSON
.
parse
(
resultBody
);
}
catch
(
e
)
{}
if
(
result
.
status
>=
200
&&
result
.
status
<=
299
)
{
if
(
options
.
transformResponse
)
{
return
options
.
transformResponse
(
resultBody
,
{
data
});
}
else
{
return
resultBody
}
}
else
{
const
error
=
{
status
:
result
.
status
,
data
:
resultBody
,
isCancelled
:
false
}
if
(
!
simulateOfflineMode
)
{
console
.
log
(
'
A request made in a test failed with the following error:
'
);
console
.
log
(
error
,
{
depth
:
null
});
console
.
log
(
`The original request:
${
method
}
${
url
}
`
);
if
(
requestBody
)
console
.
log
(
`Original payload:
${
requestBody
}
`
);
}
throw
error
}
}
// Set the correct base url to metabase/lib/api module
if
(
process
.
env
.
E2E_HOST
)
{
api
.
basename
=
process
.
env
.
E2E_HOST
;
}
else
{
console
.
log
(
'
Please use `yarn run test-integrated` or `yarn run test-integrated-watch` for running integration tests.
'
)
process
.
quit
(
0
)
}
/**
* Creates an augmented Redux store for testing the whole app including browser history manipulation. Includes:
* - A simulated browser history that is used by react-router
* - Methods for
* * manipulating the browser history
* * manipulating the
simulated
browser history
* * waiting until specific Redux actions have been dispatched
* * getting a React container subtree for the current route
*/
export
const
createTestStore
=
async
({
publicApp
=
false
,
embedApp
=
false
}
=
{})
=>
{
hasFinishedCreatingStore
=
false
;
hasStartedCreatingStore
=
true
;
...
...
@@ -195,6 +130,9 @@ const testStoreEnhancer = (createStore, history, getRoutes) => {
_latestDispatchedActions
:
[],
_finalStoreInstance
:
null
,
/**
* Redux dispatch method middleware that records all dispatched actions
*/
dispatch
:
(
action
)
=>
{
const
result
=
store
.
_originalDispatch
(
action
);
...
...
@@ -234,42 +172,40 @@ const testStoreEnhancer = (createStore, history, getRoutes) => {
if
(
allActionsAreTriggered
())
{
// Short-circuit if all action types are already in the history of dispatched actions
return
;
return
Promise
.
resolve
()
;
}
else
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
timeoutID
=
setTimeout
(()
=>
{
store
.
_onActionDispatched
=
null
;
return
reject
(
new
Error
(
`All these actions were not dispatched within
${
timeout
}
ms:\n`
+
chalk
.
cyan
(
actionTypes
.
join
(
"
\n
"
))
+
"
\n\n
Dispatched actions since the last call of `waitForActions`:
\n
"
+
(
store
.
_latestDispatchedActions
.
map
(
store
.
_formatDispatchedAction
).
join
(
"
\n
"
)
||
"
No dispatched actions
"
)
+
"
\n\n
Dispatched actions since the initialization of test suite:
\n
"
+
(
store
.
_allDispatchedActions
.
map
(
store
.
_formatDispatchedAction
).
join
(
"
\n
"
)
||
"
No dispatched actions
"
)
)
)
},
timeout
)
store
.
_onActionDispatched
=
()
=>
{
if
(
allActionsAreTriggered
())
{
store
.
_latestDispatchedActions
=
getRemainingActions
();
store
.
_onActionDispatched
=
null
;
clearTimeout
(
timeoutID
);
resolve
()
}
};
setTimeout
(()
=>
{
store
.
_onActionDispatched
=
null
;
if
(
allActionsAreTriggered
())
{
// TODO: Figure out why we sometimes end up here instead of _onActionDispatched hook
store
.
_latestDispatchedActions
=
getRemainingActions
();
resolve
()
}
else
{
return
reject
(
new
Error
(
`These actions were not dispatched within
${
timeout
}
ms:\n`
+
chalk
.
cyan
(
actionTypes
.
join
(
"
\n
"
))
+
"
\n\n
Dispatched actions since the last call of `waitForActions`:
\n
"
+
(
store
.
_latestDispatchedActions
.
map
(
store
.
_formatDispatchedAction
).
join
(
"
\n
"
)
||
"
No dispatched actions
"
)
+
"
\n\n
Dispatched actions since the initialization of test suite:
\n
"
+
(
store
.
_allDispatchedActions
.
map
(
store
.
_formatDispatchedAction
).
join
(
"
\n
"
)
||
"
No dispatched actions
"
)
)
)
}
},
timeout
)
});
}
},
logDispatchedActions
:
()
=>
{
/**
* Logs the actions that have been dispatched so far
*/
debug
:
()
=>
{
console
.
log
(
chalk
.
bold
(
"
Dispatched actions since last call of `waitForActions`:
\n
"
)
+
(
store
.
_latestDispatchedActions
.
map
(
store
.
_formatDispatchedAction
).
join
(
"
\n
"
)
||
"
No dispatched actions
"
)
+
...
...
@@ -278,6 +214,9 @@ const testStoreEnhancer = (createStore, history, getRoutes) => {
)
},
/**
* Methods for manipulating the simulated browser history
*/
pushPath
:
(
path
)
=>
history
.
push
(
path
),
goBack
:
()
=>
history
.
goBack
(),
getPath
:
()
=>
urlFormat
(
history
.
getCurrentLocation
()),
...
...
@@ -291,6 +230,12 @@ const testStoreEnhancer = (createStore, history, getRoutes) => {
}
},
/**
* For testing an individual component that is rendered to the router context.
* The component will receive the same router props as it would if it was part of the complete app component tree.
*
* This is usually a lot faster than `getAppContainer` but doesn't work well with react-router links.
*/
connectContainer
:
(
reactContainer
)
=>
{
store
.
warnIfStoreCreationNotComplete
();
...
...
@@ -304,6 +249,10 @@ const testStoreEnhancer = (createStore, history, getRoutes) => {
);
},
/**
* Renders the whole app tree.
* Useful if you want to navigate between different sections of your app in your tests.
*/
getAppContainer
:
()
=>
{
store
.
warnIfStoreCreationNotComplete
();
...
...
@@ -343,4 +292,70 @@ export const createSavedQuestion = async (unsavedQuestion) => {
return
savedQuestion
}
// Patches the metabase/lib/api module so that all API queries contain the login credential cookie.
// Needed because we are not in a real web browser environment.
api
.
_makeRequest
=
async
(
method
,
url
,
headers
,
requestBody
,
data
,
options
)
=>
{
const
headersWithSessionCookie
=
{
...
headers
,
...(
loginSession
?
{
"
Cookie
"
:
`
${
METABASE_SESSION_COOKIE
}
=
${
loginSession
.
id
}
`
}
:
{})
}
const
fetchOptions
=
{
credentials
:
"
include
"
,
method
,
headers
:
new
Headers
(
headersWithSessionCookie
),
...(
requestBody
?
{
body
:
requestBody
}
:
{})
};
let
isCancelled
=
false
if
(
options
.
cancelled
)
{
options
.
cancelled
.
then
(()
=>
{
isCancelled
=
true
;
});
}
const
result
=
simulateOfflineMode
?
{
status
:
0
,
responseText
:
''
}
:
(
await
fetch
(
api
.
basename
+
url
,
fetchOptions
));
if
(
isCancelled
)
{
throw
{
status
:
0
,
data
:
''
,
isCancelled
:
true
}
}
let
resultBody
=
null
try
{
resultBody
=
await
result
.
text
();
// Even if the result conversion to JSON fails, we still return the original text
// This is 1-to-1 with the real _makeRequest implementation
resultBody
=
JSON
.
parse
(
resultBody
);
}
catch
(
e
)
{}
if
(
result
.
status
>=
200
&&
result
.
status
<=
299
)
{
if
(
options
.
transformResponse
)
{
return
options
.
transformResponse
(
resultBody
,
{
data
});
}
else
{
return
resultBody
}
}
else
{
const
error
=
{
status
:
result
.
status
,
data
:
resultBody
,
isCancelled
:
false
}
if
(
!
simulateOfflineMode
)
{
console
.
log
(
'
A request made in a test failed with the following error:
'
);
console
.
log
(
error
,
{
depth
:
null
});
console
.
log
(
`The original request:
${
method
}
${
url
}
`
);
if
(
requestBody
)
console
.
log
(
`Original payload:
${
requestBody
}
`
);
}
throw
error
}
}
// Set the correct base url to metabase/lib/api module
if
(
process
.
env
.
E2E_HOST
)
{
api
.
basename
=
process
.
env
.
E2E_HOST
;
}
else
{
console
.
log
(
'
Please use `yarn run test-integrated` or `yarn run test-integrated-watch` for running integration tests.
'
)
process
.
quit
(
0
)
}
jasmine
.
DEFAULT_TIMEOUT_INTERVAL
=
20000
;
This diff is collapsed.
Click to expand it.
frontend/test/admin/settings/settings.integ.spec.js
+
0
−
1
View file @
3e08a935
...
...
@@ -33,7 +33,6 @@ describe("admin/settings", () => {
// clear the site name input, send the keys corresponding to the site name, then blur to trigger the update
setInputValue
(
input
,
siteName
)
input
.
simulate
(
'
blur
'
)
await
store
.
waitForActions
([
UPDATE_SETTING
])
});
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment