单个测试在 PhantomJS 中失败,但在 Chrome 和 Firefox 中有效
Single test fails in PhantomJS but works in Chrome and Firefox
我在 Ember.js 1.10、Ember CLI 0.1.12 中进行了一次验收测试,它在 PhantomJS 上失败但在 Chrome 和 Firefox 中运行良好。我已经尝试调试了 2 天,但我 运行 没有想法。测试的名称是用户在登录后可以查看仅登录的页面。基本上,当您未登录并尝试访问 classic
路由时,例如 /about
您将被重定向到经典路由 beforeModel
钩子中的 start.login
:
beforeModel: ->
if not @controllerFor('application').get 'logged'
@transitionTo 'start.login'
当您在 start.login
并提供正确的姓名和用户名时,将调用 StartLoginController
中的 logIn
操作:
logIn: ->
if not @get('logged')
@get('controllers.application').send 'logIn', @get('username'), @get('password'), @get('rememberMe')
在 ApplicationController
中调用以下操作:
actions:
logIn: (username, password, remember) ->
if not @get 'logged'
$.ajax
url: @get('apiURL') + '/auth/login'
type: 'POST'
data:
name: username
password: password
remember: remember
xhrFields:
withCredentials: true #ensure CORS
.then (response) =>
if response.success
expires = if remember then new Date(response.cookieExpiration) else null
$.cookie 'auth_user_id', response.user.id,
expires: expires
path: '/'
$.cookie 'auth_expiration', response.cookieExpiration,
expires: expires
path: '/'
@setProperties
logged: true
'controllers.auth.userId': response.user.id
@transitionToRoute 'classic.index'
, =>
@send 'openModal', 'modal/wrong-credentials'
false
即使在 PhantomJS 中也能正常工作。其他测试通过。正确调用操作,正确设置属性,正确设置 cookie。即使 beforeModel
钩子也能正确调用(或不调用)transitionTo
方法。我认为 PhantomJS 的问题与调用事物的一些异步顺序有关,但我已经尝试在许多地方将代码包装在 Ember.run
和 andThen
中。一点运气都没有。
testem.json
:
{
"framework": "qunit",
"test_page": "tests/index.html?hidepassed",
"launch_in_ci": [
"PhantomJS"
],
"launch_in_dev": [
"PhantomJS",
"Chrome",
"Firefox"
]
}
验收测试login-test.coffee
(失败测试是最后一个):
`import Ember from 'ember'`
`import startApp from '../helpers/start-app'`
application = null
run = Ember.run
login = ->
visit '/'
fillIn '[placeholder=Login]', 'test'
fillIn '[placeholder=Hasło]', 'test'
click '.button-login'
clearCookies = ->
cookies = $.cookie()
for cookie of cookies
$.removeCookie cookie,
path: '/'
cookies = document.cookie.split ';'
for i in [0...cookies.length] by 1
equals = cookies[i].indexOf '='
name = if equals > -1 then cookies[i].substr(0, equals) else cookies[i]
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT"
module 'Acceptance: Login',
setup: ->
application = startApp()
clearCookies()
time = new Date()
$.mockjaxSettings.logging = false
$.mockjax
type: 'POST'
url: 'api/v1/auth/login'
dataType: 'json'
responseText:
success: true
user:
id: 1
cookieExpiration: time.setDate time.getDate() + 14
$.mockjax
type: 'GET'
url: '/api/v1/users/1'
dataType: 'json'
responseText:
user:
id: 1
$.mockjax
type: 'GET'
url: '/api/v1/statuses' # ?limitOld=10&friends=true&comments[limit]=5
data:
comments:
limit: 5
friends: true
limitOld: 10
responseText:
statuses: {}
$.mockjax
type: 'GET'
url: '/api/v1/getRandomQuote'
$.mockjax
type: 'GET'
url: '/api/v1/statuses/?friends=true&count=true'
responseText:
count: 0
$.mockjax
type: 'GET'
url: '/api/v1/meals'
$.mockjax
type: 'GET'
url: '/api/v1/notifications'
$.mockjax
type: 'GET'
url: '/api/v1/notifications'
data:
read: false
responseText: {}
return
teardown: ->
$.mockjax.clear()
clearCookies()
run application, 'destroy'
test 'user lands on default page when he is not logged', ->
expect 1
visit '/'
andThen ->
equal currentPath(), 'start.login'
test 'login page is displayed when you are trying to access logged-only page', ->
expect 1
visit '/kitchen'
andThen ->
equal currentPath(), 'start.login'
test 'user can login', ->
expect 2
appController = application.__container__.lookup 'controller:application'
equal appController.get('logged'), false, 'user is not logged before login'
login()
andThen ->
ok appController.get 'logged', 'user is logged when response is success'
test 'user can view logged-only pages when he is logged', ->
expect 2
console.log '-- LOGGED-ONLY TEST START --'
visit '/about'
andThen ->
equal currentPath(), 'start.login'
login()
visit '/about'
andThen ->
equal currentPath(), 'classic.about'
最后测试输出:
TEST'EM 'SCRIPTS!
Open the URL below in a browser to connect.
http://localhost:7357/
━━━━━━━━━━━━━━┓
PhantomJS 1.9┃ Firefox 37.0
198/199 ✘ ┃ 199/199 ✔
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Acceptance: Login: user can view logged-only pages when he is logged
✘ failed
expected classic.about
actual start.login
-- LOGGED-ONLY TEST START --
我不认为 classic.about
是错误的来源,因为用 classic
资源的其他子路由替换它会导致相同的 PhantomJS 测试失败。
好的,看来问题出在模型中 ClassicRoute
(评论使测试通过):
model: ->
new Promise (resolve, reject) =>
@store.find 'user', @controllerFor('auth').get('userId')
.then (user) =>
@controllerFor('auth').set 'user', user
resolve
profile: user.get 'profile'
我将逻辑拆分为两个而不是一个,现在可以使用了:
beforeModel: ->
if not @controllerFor('application').get 'logged'
@transitionTo 'start.login'
else
@store
.find 'user', @controllerFor('auth').get('userId')
.then (user) =>
@controllerFor('auth').set 'user', user
@set 'profileId', user.get('profile.id')
model: ->
@store.find 'profile', @get('profileId')
我在 Ember.js 1.10、Ember CLI 0.1.12 中进行了一次验收测试,它在 PhantomJS 上失败但在 Chrome 和 Firefox 中运行良好。我已经尝试调试了 2 天,但我 运行 没有想法。测试的名称是用户在登录后可以查看仅登录的页面。基本上,当您未登录并尝试访问 classic
路由时,例如 /about
您将被重定向到经典路由 beforeModel
钩子中的 start.login
:
beforeModel: ->
if not @controllerFor('application').get 'logged'
@transitionTo 'start.login'
当您在 start.login
并提供正确的姓名和用户名时,将调用 StartLoginController
中的 logIn
操作:
logIn: ->
if not @get('logged')
@get('controllers.application').send 'logIn', @get('username'), @get('password'), @get('rememberMe')
在 ApplicationController
中调用以下操作:
actions:
logIn: (username, password, remember) ->
if not @get 'logged'
$.ajax
url: @get('apiURL') + '/auth/login'
type: 'POST'
data:
name: username
password: password
remember: remember
xhrFields:
withCredentials: true #ensure CORS
.then (response) =>
if response.success
expires = if remember then new Date(response.cookieExpiration) else null
$.cookie 'auth_user_id', response.user.id,
expires: expires
path: '/'
$.cookie 'auth_expiration', response.cookieExpiration,
expires: expires
path: '/'
@setProperties
logged: true
'controllers.auth.userId': response.user.id
@transitionToRoute 'classic.index'
, =>
@send 'openModal', 'modal/wrong-credentials'
false
即使在 PhantomJS 中也能正常工作。其他测试通过。正确调用操作,正确设置属性,正确设置 cookie。即使 beforeModel
钩子也能正确调用(或不调用)transitionTo
方法。我认为 PhantomJS 的问题与调用事物的一些异步顺序有关,但我已经尝试在许多地方将代码包装在 Ember.run
和 andThen
中。一点运气都没有。
testem.json
:
{
"framework": "qunit",
"test_page": "tests/index.html?hidepassed",
"launch_in_ci": [
"PhantomJS"
],
"launch_in_dev": [
"PhantomJS",
"Chrome",
"Firefox"
]
}
验收测试login-test.coffee
(失败测试是最后一个):
`import Ember from 'ember'`
`import startApp from '../helpers/start-app'`
application = null
run = Ember.run
login = ->
visit '/'
fillIn '[placeholder=Login]', 'test'
fillIn '[placeholder=Hasło]', 'test'
click '.button-login'
clearCookies = ->
cookies = $.cookie()
for cookie of cookies
$.removeCookie cookie,
path: '/'
cookies = document.cookie.split ';'
for i in [0...cookies.length] by 1
equals = cookies[i].indexOf '='
name = if equals > -1 then cookies[i].substr(0, equals) else cookies[i]
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT"
module 'Acceptance: Login',
setup: ->
application = startApp()
clearCookies()
time = new Date()
$.mockjaxSettings.logging = false
$.mockjax
type: 'POST'
url: 'api/v1/auth/login'
dataType: 'json'
responseText:
success: true
user:
id: 1
cookieExpiration: time.setDate time.getDate() + 14
$.mockjax
type: 'GET'
url: '/api/v1/users/1'
dataType: 'json'
responseText:
user:
id: 1
$.mockjax
type: 'GET'
url: '/api/v1/statuses' # ?limitOld=10&friends=true&comments[limit]=5
data:
comments:
limit: 5
friends: true
limitOld: 10
responseText:
statuses: {}
$.mockjax
type: 'GET'
url: '/api/v1/getRandomQuote'
$.mockjax
type: 'GET'
url: '/api/v1/statuses/?friends=true&count=true'
responseText:
count: 0
$.mockjax
type: 'GET'
url: '/api/v1/meals'
$.mockjax
type: 'GET'
url: '/api/v1/notifications'
$.mockjax
type: 'GET'
url: '/api/v1/notifications'
data:
read: false
responseText: {}
return
teardown: ->
$.mockjax.clear()
clearCookies()
run application, 'destroy'
test 'user lands on default page when he is not logged', ->
expect 1
visit '/'
andThen ->
equal currentPath(), 'start.login'
test 'login page is displayed when you are trying to access logged-only page', ->
expect 1
visit '/kitchen'
andThen ->
equal currentPath(), 'start.login'
test 'user can login', ->
expect 2
appController = application.__container__.lookup 'controller:application'
equal appController.get('logged'), false, 'user is not logged before login'
login()
andThen ->
ok appController.get 'logged', 'user is logged when response is success'
test 'user can view logged-only pages when he is logged', ->
expect 2
console.log '-- LOGGED-ONLY TEST START --'
visit '/about'
andThen ->
equal currentPath(), 'start.login'
login()
visit '/about'
andThen ->
equal currentPath(), 'classic.about'
最后测试输出:
TEST'EM 'SCRIPTS!
Open the URL below in a browser to connect.
http://localhost:7357/
━━━━━━━━━━━━━━┓
PhantomJS 1.9┃ Firefox 37.0
198/199 ✘ ┃ 199/199 ✔
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Acceptance: Login: user can view logged-only pages when he is logged
✘ failed
expected classic.about
actual start.login
-- LOGGED-ONLY TEST START --
我不认为 classic.about
是错误的来源,因为用 classic
资源的其他子路由替换它会导致相同的 PhantomJS 测试失败。
好的,看来问题出在模型中 ClassicRoute
(评论使测试通过):
model: ->
new Promise (resolve, reject) =>
@store.find 'user', @controllerFor('auth').get('userId')
.then (user) =>
@controllerFor('auth').set 'user', user
resolve
profile: user.get 'profile'
我将逻辑拆分为两个而不是一个,现在可以使用了:
beforeModel: ->
if not @controllerFor('application').get 'logged'
@transitionTo 'start.login'
else
@store
.find 'user', @controllerFor('auth').get('userId')
.then (user) =>
@controllerFor('auth').set 'user', user
@set 'profileId', user.get('profile.id')
model: ->
@store.find 'profile', @get('profileId')