and application flow. They emulate user interaction and confirm expected results. Some acceptance tests you might write are: A user is able to log in via the login form. A user is able to create a blog post. A visitor does not have access to the admin panel.
of the box. For creating your first test, you just need to run: ember generate acceptance-test <name> $ e m b e r g e n e r a t e a c c e p t a n c e t e s t u s e r c a n l o g i n v i a f o r m v e r s i o n : 1 . 1 3 . 8 i n s t a l l i n g a c c e p t a n c e t e s t c r e a t e t e s t s / a c c e p t a n c e / u s e r c a n l o g i n v i a f o r m t e s t . j s
t E m b e r f r o m ' e m b e r ' ; i m p o r t { m o d u l e , t e s t } f r o m ' q u n i t ' ; i m p o r t s t a r t A p p f r o m ' t e s t i n g e m b e r / t e s t s / h e l p e r s / s t a r t a p p ' ; m o d u l e ( ' A c c e p t a n c e | u s e r c a n l o g i n v i a f o r m ' , { b e f o r e E a c h : f u n c t i o n ( ) { t h i s . a p p l i c a t i o n = s t a r t A p p ( ) ; } , a f t e r E a c h : f u n c t i o n ( ) { E m b e r . r u n ( t h i s . a p p l i c a t i o n , ' d e s t r o y ' ) ; } } ) ; t e s t ( ' v i s i t i n g / u s e r c a n l o g i n v i a f o r m ' , f u n c t i o n ( a s s e r t ) { v i s i t ( ' / u s e r c a n l o g i n v i a f o r m ' ) ; a n d T h e n ( f u n c t i o n ( ) { a s s e r t . e q u a l ( c u r r e n t U R L ( ) , ' / u s e r c a n l o g i n v i a f o r m ' ) ; } ) ; } ) ;
your application, so each helper is only called after the previous one finishes. click(selector) fillIn(selector, text) keyEvent(selector, type, keyCode) triggerEvent(selector, type, options) visit(url)
asynchronous helpers to complete prior to progressing forward. / / t e s t s / a c c e p t a n c e / n e w p o s t a p p e a r s f i r s t t e s t . j s t e s t ( ' s i m p l e t e s t ' , f u n c t i o n ( a s s e r t ) { a s s e r t . e x p e c t ( 1 ) ; / / E n s u r e t h a t w e w i l l p e r f o r m o n e a s s e r t i o n v i s i t ( ' / p o s t s / n e w ' ) ; f i l l I n ( ' i n p u t . t i t l e ' , ' M y n e w p o s t ' ) ; c l i c k ( ' b u t t o n . s u b m i t ' ) ; / / W a i t f o r a s y n c h r o n o u s h e l p e r s a b o v e t o c o m p l e t e a n d T h e n ( f u n c t i o n ( ) { / / F i n a l l y m a k e o u r a s s e r t i o n a s s e r t . e q u a l ( f i n d ( ' u l . p o s t s l i : f i r s t ' ) . t e x t ( ) , ' M y n e w p o s t ' ) ; } ) ; } ) ;
h e l p e r s / d b l c l i c k . j s i m p o r t E m b e r f r o m ' e m b e r ' ; e x p o r t d e f a u l t E m b e r . T e s t . r e g i s t e r A s y n c H e l p e r ( ' d b l c l i c k ' , f u n c t i o n ( a p p , a s s e r t , s e l e c t o r , c o n t e x t ) { v a r $ e l = f i n d W i t h A s s e r t ( s e l e c t o r , c o n t e x t ) ; E m b e r . r u n ( f u n c t i o n ( ) { $ e l . d b l c l i c k ( ) ; } ) ; } ) ;
small piece of code and ensure that it is doing what was intended. Testing an E m b e r . O b j e c t is as simple as creating an instance of the object, setting its state, and running assertions against the object.
o d e l s / s o m e t h i n g . j s e x p o r t d e f a u l t E m b e r . O b j e c t . e x t e n d ( { f o o : ' b a r ' , t e s t M e t h o d ( ) { t h i s . s e t ( ' f o o ' , ' b a z ' ) ; } } ) ; / / t e s t s / u n i t / m o d e l s / s o m e t h i n g t e s t . j s i m p o r t { m o d u l e F o r M o d e l , t e s t } f r o m ' e m b e r q u n i t ' ; m o d u l e F o r M o d e l ( ' s o m e t h i n g ' , ' U n i t | M o d e l | s o m e t h i n g ' , { / / S p e c i f y t h e o t h e r u n i t s t h a t a r e r e q u i r e d f o r t h i s t e s t . n e e d s : [ ] } ) ; t e s t ( ' c a l l i n g t e s t M e t h o d u p d a t e d f o o ' , f u n c t i o n ( a s s e r t ) { v a r s o m e T h i n g = t h i s . s u b j e c t ( { } ) ; s o m e T h i n g . t e s t M e t h o d ( ) ; a s s e r t . e q u a l ( s o m e T h i n g . g e t ( ' f o o ' ) , ' b a z ' ) ; } ) ;
o d e l s / s o m e t h i n g . j s e x p o r t d e f a u l t E m b e r . O b j e c t . e x t e n d ( { f o o : ' b a r ' , c o m p u t e d F o o : E m b e r . c o m p u t e d ( ' f o o ' , f u n c t i o n ( ) { r e t u r n ' c o m p u t e d ' + t h i s . g e t ( ' f o o ' ) ; } ) } ) ; / / t e s t s / u n i t / m o d e l s / s o m e t h i n g t e s t . j s i m p o r t { m o d u l e F o r M o d e l , t e s t } f r o m ' e m b e r q u n i t ' ; m o d u l e F o r M o d e l ( ' s o m e t h i n g ' , ' U n i t | M o d e l | s o m e t h i n g ' , { / / S p e c i f y t h e o t h e r u n i t s t h a t a r e r e q u i r e d f o r t h i s t e s t . n e e d s : [ ] } ) ; t e s t ( ' c o m p u t e d F o o c o r r e c t l y c o n c a t s f o o ' , f u n c t i o n ( a s s e r t ) { v a r s o m e T h i n g = t h i s . s u b j e c t ( { } ) ; s o m e T h i n g . s e t ( ' f o o ' , ' b a z ' ) ; a s s e r t . e q u a l ( s o m e T h i n g . g e t ( ' c o m p u t e d F o o ' ) , ' c o m p u t e d b a z ' ) ; } ) ;
d e l s / s o m e t h i n g . j s e x p o r t d e f a u l t E m b e r . O b j e c t . e x t e n d ( { f o o : ' b a r ' , o t h e r : ' n o ' , d o S o m e t h i n g : E m b e r . o b s e r v e r ( ' f o o ' , f u n c t i o n ( ) { t h i s . s e t ( ' o t h e r ' , ' y e s ' ) ; } ) } ) ; / / t e s t s / u n i t / m o d e l s / s o m e t h i n g t e s t . j s i m p o r t { m o d u l e F o r M o d e l , t e s t } f r o m ' e m b e r q u n i t ' ; m o d u l e F o r M o d e l ( ' s o m e t h i n g ' , ' U n i t | M o d e l | s o m e t h i n g ' , { / / S p e c i f y t h e o t h e r u n i t s t h a t a r e r e q u i r e d f o r t h i s t e s t . n e e d s : [ ] } ) ; t e s t ( ' d o S o m e t h i n g o b s e r v e r s e t s o t h e r p r o p ' , f u n c t i o n ( ) { v a r s o m e T h i n g = t h i s . s u b j e c t ( { } ) ; s o m e T h i n g . s e t ( ' f o o ' , ' b a z ' ) ; e q u a l ( s o m e T h i n g . g e t ( ' o t h e r ' ) , ' y e s ' ) ; } ) ;
to a number of test helpers: moduleFor(fullName [, description [, callbacks]]) fullName: The full name of the unit, (ie. controller:application, route:index, etc.) description: the description of the module callbacks: normal QUnit callbacks (setup and teardown), with addition to needs. moduleForComponent(name [, description [, callbacks]]) name: the short name of the component that you'd use in a template, (ie. x-foo, ic-tabs, etc.) description: the description of the module callbacks: normal QUnit callbacks (setup and teardown), with addition to needs. moduleForModel(name [, description [, callbacks]]) name: the short name of the model you'd use in store operations (ie. user, assignmentGroup, etc.) description: the description of the module callbacks: normal QUnit callbacks (setup and teardown), with addition to needs. test(description, callbacks) setResolver
application, you need to let Ember know it is in test mode. E m b e r . s e t u p F o r T e s t i n g ( ) This call TURN OFF the Ember run loop execution.
C o m p o n e n t extends E m b e r . O b j e c t too i m p o r t { t e s t , m o d u l e F o r C o m p o n e n t } f r o m ' e m b e r q u n i t ' ; m o d u l e F o r C o m p o n e n t ( ' x f o o ' , { u n i t : t r u e , n e e d s : [ ] } ) ; / / r u n a t e s t t e s t ( ' i t r e n d e r s ' , f u n c t i o n ( a s s e r t ) { a s s e r t . e x p e c t ( 1 ) ; / / c r e a t e s t h e c o m p o n e n t i n s t a n c e v a r s u b j e c t = t h i s . s u b j e c t ( ) ; / / r e n d e r t h e c o m p o n e n t o n t h e p a g e t h i s . r e n d e r ( ) ; a s s e r t . e q u a l ( t h i s . $ ( ' . f o o ' ) . t e x t ( ) , ' b a r ' ) ; } ) ;
in JavaScript. And you will never use an Ember component in this way on your production code. Components are integrated into your app with templates, and you don't set attributes on them directly either.
b s f r o m ' h t m l b a r s i n l i n e p r e c o m p i l e ' ; i m p o r t { t e s t , m o d u l e F o r C o m p o n e n t } f r o m ' e m b e r q u n i t ' ; m o d u l e F o r C o m p o n e n t ( ' x f o o ' , { i n t e g r a t i o n : t r u e } ) ; t e s t ( ' i t r e n d e r s ' , f u n c t i o n ( a s s e r t ) { a s s e r t . e x p e c t ( 2 ) ; / / s e t u p t h e o u t e r c o n t e x t t h i s . s e t ( ' v a l u e ' , ' c a t ' ) ; t h i s . o n ( ' a c t i o n ' , f u n c t i o n ( r e s u l t ) { a s s e r t . e q u a l ( r e s u l t , ' b a r ' ) ; } ) ; / / r e n d e r t h e c o m p o n e n t t h i s . r e n d e r ( h b s ` { { x f o o v a l u e = v a l u e a c t i o n = " r e s u l t " } } ` ) ; a s s e r t . e q u a l ( t h i s . $ ( ' d i v > . v a l u e ' ) . t e x t ( ) , ' c a t ' ) ; t h i s . $ ( ' b u t t o n ' ) . c l i c k ( ) ; } ) ;
C o n t r o l l e r e x p o r t d e f a u l t E m b e r . C o n t r o l l e r . e x t e n d ( { p r o p A : ' Y o u n e e d t o w r i t e t e s t s ' , p r o p B : ' A n d w r i t e o n e f o r m e t o o ' , s e t P r o p B ( s t r ) { t h i s . s e t ( ' p r o p B ' , s t r ) ; } , a c t i o n s : { s e t P r o p s ( s t r ) { t h i s . s e t ( ' p r o p A ' , ' T e s t i n g i s c o o l ' ) ; t h i s . s e t P r o p B ( s t r ) ; } } } ) ;
m o d u l e F o r , t e s t } f r o m ' e m b e r q u n i t ' ; m o d u l e F o r ( ' c o n t r o l l e r : p o s t s t e s t ' , { / / S p e c i f y t h e o t h e r u n i t s t h a t a r e r e q u i r e d f o r t h i s t e s t . / / n e e d s : [ ' c o n t r o l l e r : f o o ' ] } ) ; t e s t ( ' c a l l i n g t h e a c t i o n s e t P r o p s u p d a t e s p r o p s ' , f u n c t i o n ( a s s e r t ) { a s s e r t . e x p e c t ( 2 ) ; / / g e t t h e c o n t r o l l e r i n s t a n c e v a r c t r l = t h i s . s u b j e c t ( ) ; / / t r i g g e r t h e a c t i o n o n t h e c o n t r o l l e r b y u s i n g t h e ` s e n d ` m e t h o d , / / p a s s i n g i n a n y p a r a m s t h a t o u r a c t i o n m a y b e e x p e c t i n g c t r l . s e n d ( ' s e t P r o p s ' , ' T e s t i n g R o c k s ! ' ) ; / / f i n a l l y w e a s s e r t t h a t o u r v a l u e s h a v e b e e n u p d a t e d / / b y t r i g g e r i n g o u r a c t i o n . a s s e r t . e q u a l ( c t r l . g e t ( ' p r o p A ' ) , ' T e s t i n g i s c o o l ' ) ; a s s e r t . e q u a l ( c t r l . g e t ( ' p r o p B ' ) , ' T e s t i n g R o c k s ! ' ) ; } ) ;
c a t i o n R o u t e with an alert function d i s p l a y A l e r t : e x p o r t d e f a u l t E m b e r . R o u t e . e x t e n d ( { a c t i o n s : { d i s p l a y A l e r t ( t e x t ) { t h i s . _ d i s p l a y A l e r t ( t e x t ) ; } } , _ d i s p l a y A l e r t ( t e x t ) { a l e r t ( t e x t ) ; } } ) ;
n d o w . a l e r t function / / t e s t s / u n i t / r o u t e s / a p p l i c a t i o n t e s t . j s v a r o r i g i n a l A l e r t ; m o d u l e F o r ( ' r o u t e : a p p l i c a t i o n ' , { b e f o r e E a c h ( ) { o r i g i n a l A l e r t = w i n d o w . a l e r t ; / / s t o r e a r e f e r e n c e t o w i n d o w . a l e r t } , a f t e r E a c h ( ) { w i n d o w . a l e r t = o r i g i n a l A l e r t ; / / r e s t o r e o r i g i n a l w i n d o w . a l e r t } } ) ;
u n i t / r o u t e s / a p p l i c a t i o n t e s t . j s t e s t ( ' A l e r t i s c a l l e d o n d i s p l a y A l e r t ' , f u n c t i o n ( a s s e r t ) { a s s e r t . e x p e c t ( 2 ) ; v a r r o u t e = t h i s . s u b j e c t ( ) ; / / g e t t h e r o u t e i n s t a n c e v a r e x p e c t e d T e x t ; e x p e c t e d T e x t = ' f o o ' ; w i n d o w . a l e r t = f u n c t i o n ( t e x t ) { a s s e r t . e q u a l ( t e x t , e x p e c t e d T e x t ) } ; r o u t e . _ d i s p l a y A l e r t ( e x p e c t e d T e x t ) ; e x p e c t e d T e x t = ' b a r ' ; w i n d o w . a l e r t = f u n c t i o n ( t e x t ) { a s s e r t . e q u a l ( t e x t , e x p e c t e d T e x t ) } ; r o u t e . s e n d ( ' d i s p l a y A l e r t ' , e x p e c t e d T e x t ) ; } ) ;
a p p / m o d e l s / p l a y e r . j s e x p o r t d e f a u l t D S . M o d e l . e x t e n d ( { l e v e l : D S . a t t r ( ' n u m b e r ' , { d e f a u l t V a l u e : 0 } ) , l e v e l N a m e : D S . a t t r ( ' s t r i n g ' , { d e f a u l t V a l u e : ' N o o b ' } ) , l e v e l U p ( ) { v a r n e w L e v e l = t h i s . i n c r e m e n t P r o p e r t y ( ' l e v e l ' ) ; i f ( n e w L e v e l = = = 5 ) { t h i s . s e t ( ' l e v e l N a m e ' , ' P r o f e s s i o n a l ' ) ; } } } ) ;
m o d u l e F o r M o d e l helper: m o d u l e F o r M o d e l ( ' p l a y e r ' ) ; t e s t ( ' l e v e l U p ' , f u n c t i o n ( a s s e r t ) { / / t h i s . s u b j e c t a l i a s e s t h e c r e a t e R e c o r d m e t h o d o n t h e m o d e l v a r p l a y e r = t h i s . s u b j e c t ( { l e v e l : 4 } ) ; / / w r a p a s y n c h r o n o u s c a l l i n r u n l o o p E m b e r . r u n ( f u n c t i o n ( ) { p l a y e r . l e v e l U p ( ) ; } ) ; a s s e r t . e q u a l ( p l a y e r . g e t ( ' l e v e l ' ) , 5 ) ; a s s e r t . e q u a l ( p l a y e r . g e t ( ' l e v e l N a m e ' ) , ' P r o f e s s i o n a l ' ) ; } ) ;
own a P r o f i l e . / / a p p / m o d e l s / p r o f i l e . j s e x p o r t d e f a u l t D S . M o d e l . e x t e n d ( { / / c o d e . . . } ) ; / / a p p / m o d e l s / u s e r . j s e x p o r t d e f a u l t D S . M o d e l . e x t e n d ( { p r o f i l e : D S . b e l o n g s T o ( ' p r o f i l e ' ) / / c o d e . . . } ) ;
wired up correctly. / / t e s t s / u n i t / m o d e l s / u s e r t e s t . j s m o d u l e F o r M o d e l ( ' u s e r ' , { / / S p e c i f y t h e o t h e r u n i t s t h a t a r e r e q u i r e d f o r t h i s t e s t . n e e d s : [ ' m o d e l : p r o f i l e ' ] } ) ; t e s t ( ' p r o f i l e r e l a t i o n s h i p ' , f u n c t i o n ( a s s e r t ) { v a r U s e r = t h i s . s t o r e ( ) . m o d e l F o r ( ' u s e r ' ) ; v a r p r o f i l e = E m b e r . g e t ( U s e r , ' r e l a t i o n s h i p s B y N a m e ' ) . g e t ( ' p r o f i l e ' ) ; a s s e r t . e q u a l ( p r o f i l e . k e y , ' p r o f i l e ' ) ; a s s e r t . e q u a l ( p r o f i l e . k i n d , ' b e l o n g s T o ' ) ; } ) ;