From 9fc7956f65950e3c46723f047cc687f6145d54e6 Mon Sep 17 00:00:00 2001 From: Josh Smith Date: Thu, 23 Mar 2017 21:23:58 -0700 Subject: [PATCH] Make the onboarding flow more flexible --- app/components/thank-you-container.js | 7 +- app/controllers/application.js | 3 +- app/mixins/onboarding-controller.js | 41 +++++-- app/mixins/onboarding-route.js | 34 ------ app/models/user.js | 1 + app/router.js | 23 ++-- app/routes/application.js | 75 ++++++------ app/routes/project/checkout.js | 4 +- app/routes/project/donate.js | 29 ++++- app/routes/signup.js | 21 ++-- app/routes/start.js | 3 +- app/routes/start/expertise.js | 3 +- app/routes/start/hello.js | 3 +- app/routes/start/interests.js | 3 +- app/routes/start/skills.js | 3 +- app/services/navigation-menu.js | 24 +++- app/services/onboarding.js | 71 +++++++---- app/services/user-subscriptions.js | 6 +- app/styles/_alerts.scss | 2 +- app/styles/layout/_header.scss | 11 +- .../components/create-comment-form.hbs | 2 +- app/templates/components/navigation-menu.hbs | 20 +++- .../components/project-long-description.hbs | 3 +- app/templates/components/signup-form.hbs | 2 +- .../components/thank-you-container.hbs | 6 +- app/templates/index.hbs | 4 +- mirage/config.js | 4 +- tests/acceptance/logout-test.js | 2 +- tests/acceptance/navigation-test.js | 10 +- tests/acceptance/project-checkout-test.js | 5 +- tests/acceptance/project-donate-test.js | 10 +- tests/acceptance/signup-test.js | 4 +- .../donations/donation-progress-test.js | 4 +- .../components/navigation-menu-test.js | 112 ++++++++++++++---- .../components/signup-form-test.js | 4 +- .../components/donations/donation-progress.js | 5 +- tests/pages/components/navigation-menu.js | 46 +++++-- tests/pages/oauth/stripe.js | 0 tests/unit/mixins/onboarding-route-test.js | 14 --- tests/unit/models/user-test.js | 3 +- tests/unit/services/onboarding-test.js | 71 ++++------- yarn.lock | 16 ++- 42 files changed, 434 insertions(+), 280 deletions(-) delete mode 100644 app/mixins/onboarding-route.js delete mode 100644 tests/pages/oauth/stripe.js delete mode 100644 tests/unit/mixins/onboarding-route-test.js diff --git a/app/components/thank-you-container.js b/app/components/thank-you-container.js index 5b5c9d24e..192171417 100644 --- a/app/components/thank-you-container.js +++ b/app/components/thank-you-container.js @@ -1,9 +1,12 @@ import Ember from 'ember'; const { - Component + Component, + inject: { service } } = Ember; export default Component.extend({ - classNames: ['thank-you-container'] + classNames: ['thank-you-container'], + + onboarding: service() }); diff --git a/app/controllers/application.js b/app/controllers/application.js index 6b9dee9af..f6804fa52 100644 --- a/app/controllers/application.js +++ b/app/controllers/application.js @@ -3,6 +3,7 @@ import Ember from 'ember'; const { computed, Controller, + get, inject: { service } } = Ember; @@ -22,7 +23,7 @@ export default Controller.extend({ actions: { invalidateSession() { - this.get('session').invalidate(); + get(this, 'session').invalidate(); } } }); diff --git a/app/mixins/onboarding-controller.js b/app/mixins/onboarding-controller.js index 2973dc975..e023f7776 100644 --- a/app/mixins/onboarding-controller.js +++ b/app/mixins/onboarding-controller.js @@ -2,8 +2,11 @@ import Ember from 'ember'; const { computed, + get, + getProperties, inject: { service }, - Mixin + Mixin, + set } = Ember; export default Mixin.create({ @@ -14,14 +17,34 @@ export default Mixin.create({ actions: { continue() { - let user = this.get('user'); - let onboarding = this.get('onboarding'); - let nextStateTransition = onboarding.get('nextStateTransition'); - let nextRoute = onboarding.get('nextRoute'); - user.set('stateTransition', nextStateTransition); - user.save().then(() => { - this.transitionToRoute(nextRoute); - }); + let { onboarding, user } = getProperties(this, 'onboarding', 'user'); + let { nextStateTransition, shouldTransitionUser } = getProperties(onboarding, 'nextStateTransition', 'shouldTransitionUser'); + + // We can transition routes without transitioning the user's state + if (shouldTransitionUser) { + set(user, 'stateTransition', nextStateTransition); + } + + this._transitionToNextRoute(); + }, + + skip() { + let { onboarding, user } = getProperties(this, 'onboarding', 'user'); + let { skipStateTransition, shouldTransitionUser } = getProperties(onboarding, 'skipStateTransition', 'shouldTransitionUser'); + + // We can transition routes without transitioning the user's state + if (shouldTransitionUser) { + set(user, 'stateTransition', skipStateTransition); + } + + this._transitionToNextRoute(); } + }, + + _transitionToNextRoute() { + let { onboarding, user } = getProperties(this, 'onboarding', 'user'); + user.save().then(() => { + this.transitionToRoute(get(onboarding, 'nextRoute')); + }); } }); diff --git a/app/mixins/onboarding-route.js b/app/mixins/onboarding-route.js deleted file mode 100644 index a40efd226..000000000 --- a/app/mixins/onboarding-route.js +++ /dev/null @@ -1,34 +0,0 @@ -import Ember from 'ember'; - -const { - inject: { service }, - Mixin -} = Ember; - -export default Mixin.create({ - currentUser: service(), - onboarding: service(), - - beforeModel(transition) { - let isOnboarding = this.get('onboarding.isOnboarding'); - let expectedOnboardingRoute = this.get('onboarding.currentRoute'); - let routes = this.get('onboarding.routes'); - let target = transition.targetName; - let user = this.get('currentUser.user'); - if (isOnboarding && target !== expectedOnboardingRoute) { - this._abortAndFixHistory(transition); - } else if (isOnboarding) { - return this._super(...arguments); - } else if (user && routes.includes(target)) { - this._abortAndFixHistory(transition); - this.transitionTo('projects-list'); - } - }, - - _abortAndFixHistory(transition) { - transition.abort(); - if (window.history) { - window.history.forward(); - } - } -}); diff --git a/app/models/user.js b/app/models/user.js index 7e3a20784..c7f8aa4cd 100644 --- a/app/models/user.js +++ b/app/models/user.js @@ -16,6 +16,7 @@ export default Model.extend({ password: attr(), photoLargeUrl: attr(), photoThumbUrl: attr(), + signUpContext: attr(), state: attr(), twitter: attr(), username: attr(), diff --git a/app/router.js b/app/router.js index 3dd56a1c5..ef1d13e46 100644 --- a/app/router.js +++ b/app/router.js @@ -29,10 +29,12 @@ let AppRouter = Router.extend({ }); AppRouter.map(function() { + this.route('about'); + this.route('login'); - this.route('oauth-stripe', { - path: '/oauth/stripe' + this.route('organization', function() { + this.route('settings', function() { }); }); this.route('organizations', function() { @@ -45,6 +47,8 @@ AppRouter.map(function() { }); }); + this.route('privacy'); + this.route('project', { path: '/:slugged_route_slug/:project_slug' }, function() { this.route('checkout'); this.route('donate'); @@ -77,6 +81,10 @@ AppRouter.map(function() { this.route('signup'); + this.route('slugged-route', { + path: '/:slugged_route_slug' + }); + this.route('start', function() { this.route('hello'); this.route('interests'); @@ -84,18 +92,7 @@ AppRouter.map(function() { this.route('skills'); }); - this.route('slugged-route', { - path: '/:slugged_route_slug' - }); - this.route('team'); - this.route('about'); - - this.route('organization', function() { - this.route('settings', function() { }); - }); - - this.route('privacy'); this.route('terms'); }); diff --git a/app/routes/application.js b/app/routes/application.js index 06a9c3cba..c4a00f62b 100644 --- a/app/routes/application.js +++ b/app/routes/application.js @@ -19,7 +19,7 @@ export default Route.extend(ApplicationRouteMixin, LoadingBar, { onboarding: service(), isOnboarding: computed.alias('onboarding.isOnboarding'), - onboardingRoute: computed.alias('onboarding.currentRoute'), + onboardingRoute: computed.alias('onboarding.routeForCurrentStep'), headTags: [ { @@ -153,19 +153,21 @@ export default Route.extend(ApplicationRouteMixin, LoadingBar, { ], beforeModel(transition) { - return this._loadCurrentUser().then(() => { - if (this._shouldTransitionToOnboardingRoute(transition)) { - return this.transitionTo(get(this, 'onboardingRoute')); - } else { - return this._super(...arguments); - } - }).catch(() => this._invalidateSession()); + return this._loadCurrentUser() + .then(() => { + if (this._shouldRedirectToOnboarding(transition)) { + return this.transitionTo(get(this, 'onboardingRoute')); + } else { + return this._super(...arguments); + } + }) + .catch(() => this._invalidateSession()); }, sessionAuthenticated() { return this._loadCurrentUser() .then(() => { - this._attemptTransition(); + this._attemptTransitionAfterAuthentication(); this._trackAuthentication(); }) .catch(() => this._invalidateSession()); @@ -173,15 +175,16 @@ export default Route.extend(ApplicationRouteMixin, LoadingBar, { actions: { willTransition(transition) { - if (this._shouldTransitionToOnboardingRoute(transition)) { - this._abortAndFixHistory(transition); + if (this._shouldRedirectToOnboarding(transition)) { + transition.abort(); + this.transitionTo(get(this, 'onboardingRoute')); } }, // see https://github.com/emberjs/ember.js/issues/12791 // if we don't handle the error action at application level - // te error will continue to be thrown, causing tests to fail - // and the error to be outputed to console, even though we technically + // the error will continue to be thrown, causing tests to fail + // and the error will output to console, even though we technically // "handled" it with our application_error route/template error(e) { console.error(e); @@ -189,24 +192,24 @@ export default Route.extend(ApplicationRouteMixin, LoadingBar, { } }, - _abortAndFixHistory(transition) { - transition.abort(); - if (window.history) { - window.history.forward(); - } - }, - - _attemptTransition() { - if (get(this, 'isOnboarding')) { + // The default beahavior for an ember-simple-auth ApplicationRouteMixin is to + // Either got back to the route the user tried to access before being + // redirected to login/signup, or if there is no such route, go to the default + // route. + // + // This slightly extends this behavior by sending the user to the onboarding + // route if it's determined that should be the case. If there was a stored + // route, for example, if a non-signed-in user tried to donate, then that + // still takes precedence. + _attemptTransitionAfterAuthentication() { + let attemptedTransition = get(this, 'session.attemptedTransition'); + if (isPresent(attemptedTransition)) { + attemptedTransition.retry(); + set(this, 'session.attemptedTransition', null); + } else if (get(this, 'isOnboarding')) { this.transitionTo(get(this, 'onboardingRoute')); } else { - let attemptedTransition = get(this, 'session.attemptedTransition'); - if (isPresent(attemptedTransition)) { - attemptedTransition.retry(); - set(this, 'session.attemptedTransition', null); - } else { - this.transitionTo('projects-list'); - } + this.transitionTo('projects-list'); } }, @@ -218,14 +221,18 @@ export default Route.extend(ApplicationRouteMixin, LoadingBar, { return get(this, 'currentUser').loadCurrentUser(); }, - _shouldTransitionToOnboardingRoute(transition) { + // If the user is still in the process of onboarding, they are allowd to visit + // only select routes. Trying to access any other route redirects them to + // their next onboarding route. + // + // This function returns true if that should happen. + _shouldRedirectToOnboarding(transition) { let isOnboarding = get(this, 'isOnboarding'); - - let onboardingRoutes = get(this, 'onboarding.routes'); + let allowedRoutes = get(this, 'onboarding.allowedRoutes'); let targetRoute = transition.targetName; - let isTransitionToOnboardingRoute = (onboardingRoutes.indexOf(targetRoute) > -1); + let isTransitionToAllowedRoute = (allowedRoutes.indexOf(targetRoute) > -1); - return isOnboarding && !isTransitionToOnboardingRoute; + return isOnboarding && !isTransitionToAllowedRoute; }, _trackAuthentication() { diff --git a/app/routes/project/checkout.js b/app/routes/project/checkout.js index cb9981a57..e2ea53e5c 100644 --- a/app/routes/project/checkout.js +++ b/app/routes/project/checkout.js @@ -21,7 +21,7 @@ export default Route.extend({ return this._super(...arguments); } else { set(session, 'attemptedTransition', transition); - let queryParams = { donate: true }; + let queryParams = { context: 'donation' }; return this.transitionTo('signup', { queryParams }); } }, @@ -38,7 +38,7 @@ export default Route.extend({ get(this, 'flashMessages').success(ALREADY_A_SUBSCRIBER); this.transitionTo('project', project); } else { - this._super.call(...arguments); + this._super(...arguments); } }, diff --git a/app/routes/project/donate.js b/app/routes/project/donate.js index 129da09c2..8efe77672 100644 --- a/app/routes/project/donate.js +++ b/app/routes/project/donate.js @@ -1,12 +1,37 @@ import Ember from 'ember'; const { - Route + get, + inject: { service }, + Route, + RSVP } = Ember; +const ALREADY_A_SUBSCRIBER = "You're already supporting this project."; + export default Route.extend({ + flashMessages: service(), + session: service(), + userSubscriptions: service(), + model() { - return this.modelFor('project').reload(); + return this.modelFor('project').reload().then((project) => { + let subscription = get(this, 'userSubscriptions').fetchForProject(project); + return RSVP.hash({ project, subscription }); + }); + }, + + afterModel({ project, subscription }) { + if (subscription) { + get(this, 'flashMessages').success(ALREADY_A_SUBSCRIBER); + this.transitionTo('project', project); + } else { + this._super(...arguments); + } + }, + + setupController(controller, models) { + controller.setProperties(models); }, renderTemplate() { diff --git a/app/routes/signup.js b/app/routes/signup.js index d73acd14a..98887ffbe 100644 --- a/app/routes/signup.js +++ b/app/routes/signup.js @@ -10,24 +10,25 @@ const { } = Ember; export default Route.extend(UnauthenticatedRouteMixin, { - queryParams: { donate: false }, + queryParams: { context: 'default' }, + + session: service(), /** * Model hook initializes and returns a new user record * - * There is a specific case when an unauthenticated user will navigate to the - * project.donate route. They will get redirected to signup here, with a - * `donate=true` query parameter. - * - * This changes initialization of the user so they start with a 'donating' - * state, instead of the default 'signing_up'. + * We can pass a context of the signup, e.g. `'donating'` */ - model({ donate }) { - let user = donate ? { state: 'signed_up_donating' } : {}; + model({ context }) { + let user = context ? { signUpContext: context } : {}; return get(this, 'store').createRecord('user', user); }, - session: service(), + resetController(controller, isExiting) { + if (isExiting) { + controller.set('context', 'default'); + } + }, actions: { signIn(credentials) { diff --git a/app/routes/start.js b/app/routes/start.js index 218aea244..829cec108 100644 --- a/app/routes/start.js +++ b/app/routes/start.js @@ -1,7 +1,6 @@ import Ember from 'ember'; import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin'; -import OnboardingRouteMixin from '../mixins/onboarding-route'; const { Route } = Ember; -export default Route.extend(OnboardingRouteMixin, AuthenticatedRouteMixin, { }); +export default Route.extend(AuthenticatedRouteMixin, { }); diff --git a/app/routes/start/expertise.js b/app/routes/start/expertise.js index 438abfd06..53e9bf681 100644 --- a/app/routes/start/expertise.js +++ b/app/routes/start/expertise.js @@ -1,12 +1,11 @@ import Ember from 'ember'; -import OnboardingRouteMixin from '../../mixins/onboarding-route'; const { Route, inject: { service } } = Ember; -export default Route.extend(OnboardingRouteMixin, { +export default Route.extend({ currentUser: service(), beforeModel() { diff --git a/app/routes/start/hello.js b/app/routes/start/hello.js index a54e3f4ed..48d16e2fe 100644 --- a/app/routes/start/hello.js +++ b/app/routes/start/hello.js @@ -1,12 +1,11 @@ import Ember from 'ember'; -import OnboardingRouteMixin from '../../mixins/onboarding-route'; const { Route, inject: { service } } = Ember; -export default Route.extend(OnboardingRouteMixin, { +export default Route.extend({ currentUser: service(), model() { diff --git a/app/routes/start/interests.js b/app/routes/start/interests.js index 3b37c6831..dd291a76b 100644 --- a/app/routes/start/interests.js +++ b/app/routes/start/interests.js @@ -1,9 +1,8 @@ import Ember from 'ember'; -import OnboardingRouteMixin from '../../mixins/onboarding-route'; const { Route } = Ember; -export default Route.extend(OnboardingRouteMixin, { +export default Route.extend({ model() { return this.store.findAll('category'); } diff --git a/app/routes/start/skills.js b/app/routes/start/skills.js index e79336879..a5984c1f3 100644 --- a/app/routes/start/skills.js +++ b/app/routes/start/skills.js @@ -1,9 +1,8 @@ import Ember from 'ember'; -import OnboardingRouteMixin from '../../mixins/onboarding-route'; const { get, inject: { service }, Route } = Ember; -export default Route.extend(OnboardingRouteMixin, { +export default Route.extend({ currentUser: service(), store: service(), userSkillsList: service(), diff --git a/app/services/navigation-menu.js b/app/services/navigation-menu.js index 82fd4c51a..2c5faa25d 100644 --- a/app/services/navigation-menu.js +++ b/app/services/navigation-menu.js @@ -2,23 +2,37 @@ import Ember from 'ember'; const { computed, + computed: { alias, equal }, get, inject: { service }, Service } = Ember; export default Service.extend({ + currentUser: service(), onboarding: service(), + routing: service('-routing'), - isDefault: computed.equal('menuType', 'default'), - isOnboarding: computed.equal('menuType', 'onboarding'), + currentRouteName: alias('routing.currentRouteName'), - menuType: computed('onboarding.isOnboarding', function() { + hasDonated: computed('user', function() { + let user = get(this, 'user'); + return user.hasMany('stripeConnectSubscriptions').value() !== null; + }), + + isDefault: equal('menuType', 'default'), + isOnboarding: equal('menuType', 'onboarding'), + isViewingOnboarding: alias('onboarding.isViewingOnboarding'), + + menuType: computed('onboarding.isOnboarding', 'isViewingOnboarding', function() { let isOnboarding = get(this, 'onboarding.isOnboarding'); - if (isOnboarding) { + let isViewingOnboarding = get(this, 'isViewingOnboarding'); + if (isOnboarding || isViewingOnboarding) { return 'onboarding'; } else { return 'default'; } - }) + }), + + user: alias('currentUser.user') }); diff --git a/app/services/onboarding.js b/app/services/onboarding.js index 78b868d72..34fdee23e 100644 --- a/app/services/onboarding.js +++ b/app/services/onboarding.js @@ -2,66 +2,95 @@ import Ember from 'ember'; const { computed, + computed: { alias, equal, mapBy, or, union }, + get, + getProperties, inject: { service }, Service } = Ember; export default Service.extend({ currentUser: service(), - totalSteps: computed.alias('_steps.length'), + routing: service('-routing'), _steps: [ { number: 1, state: 'signed_up', - currentRoute: 'start.hello', + route: 'start.hello', nextRoute: 'start.interests', nextStateTransition: 'edit_profile' }, { number: 2, state: 'edited_profile', - currentRoute: 'start.interests', + route: 'start.interests', nextRoute: 'start.expertise', nextStateTransition: 'select_categories' }, { number: 3, state: 'selected_categories', - currentRoute: 'start.expertise', + route: 'start.expertise', nextRoute: 'start.skills', nextStateTransition: 'select_roles' }, { number: 4, state: 'selected_roles', - currentRoute: 'start.skills', + route: 'start.skills', nextRoute: 'projects-list', nextStateTransition: 'select_skills' } ], _currentStep: computed('currentUser.user.state', function() { - let state = this.get('currentUser.user.state'); - let steps = this.get('_steps'); + let state = get(this, 'currentUser.user.state'); + let steps = get(this, '_steps'); return steps.find((step) => { return step.state === state; }); }), - currentRoute: computed.alias('_currentStep.currentRoute'), - currentStepNumber: computed.alias('_currentStep.number'), - currentStepState: computed.alias('_currentStep.state'), - isEditingProfile: computed.equal('currentStepState', 'signed_up'), - isOnboarding: computed.or('isEditingProfile', 'isSelectingCategories', 'isSelectingRoles', 'isSelectingSkills'), - isSelectingCategories: computed.equal('currentStepState', 'edited_profile'), - isSelectingRoles: computed.equal('currentStepState', 'selected_categories'), - isSelectingSkills: computed.equal('currentStepState', 'selected_roles'), - nextRoute: computed.alias('_currentStep.nextRoute'), - nextStateTransition: computed.alias('_currentStep.nextStateTransition'), - routes: computed.mapBy('_steps', 'currentRoute'), + _currentRouteStep: computed('currentRouteName', function() { + let currentRouteName = get(this, 'currentRouteName'); + let steps = get(this, '_steps'); + return steps.find((step) => { + return step.route === currentRouteName; + }); + }), + + _allowedRoutes: [ + 'privacy', + 'project.checkout', + 'project.donate', + 'project.thank-you', + 'terms' + ], - progressPercentage: computed('currentStepNumber', 'totalSteps', function() { - return (this.get('currentStepNumber') / this.get('totalSteps')) * 100; - }) + allowedRoutes: union('_allowedRoutes', 'onboardingRoutes'), + currentRouteName: alias('routing.currentRouteName'), + currentRouteStepNumber: alias('_currentRouteStep.number'), + currentStepState: alias('_currentStep.state'), + isOnboarding: or('shouldEditProfile', 'shouldSelectCategories', 'shouldSelectRoles', 'shouldSelectSkills'), + isViewingOnboarding: computed('currentRouteName', 'onboardingRoutes', function() { + let { currentRouteName, onboardingRoutes } = getProperties(this, 'currentRouteName', 'onboardingRoutes'); + return onboardingRoutes.includes(currentRouteName); + }), + nextRoute: alias('_currentRouteStep.nextRoute'), + nextStateTransition: alias('_currentStep.nextStateTransition'), + onboardingRoutes: mapBy('_steps', 'route'), + progressPercentage: computed('currentRouteStepNumber', 'totalSteps', function() { + return (get(this, 'currentRouteStepNumber') / get(this, 'totalSteps')) * 100; + }), + routeForCurrentStep: alias('_currentStep.route'), + shouldEditProfile: equal('currentStepState', 'signed_up'), + shouldSelectCategories: equal('currentStepState', 'edited_profile'), + shouldSelectRoles: equal('currentStepState', 'selected_categories'), + shouldSelectSkills: equal('currentStepState', 'selected_roles'), + shouldTransitionUser: computed('currentRouteName', 'routeForCurrentStep', function() { + let { currentRouteName, routeForCurrentStep } = getProperties(this, 'currentRouteName', 'routeForCurrentStep'); + return currentRouteName === routeForCurrentStep; + }), + totalSteps: alias('_steps.length') }); diff --git a/app/services/user-subscriptions.js b/app/services/user-subscriptions.js index dad72b131..0b18f256b 100644 --- a/app/services/user-subscriptions.js +++ b/app/services/user-subscriptions.js @@ -2,6 +2,7 @@ import Ember from 'ember'; const { computed, + get, inject: { service }, RSVP, Service @@ -9,15 +10,14 @@ const { export default Service.extend({ currentUser: service(), - store: service(), user: computed.alias('currentUser.user'), fetchForProject(project) { - let user = this.get('user'); + let user = get(this, 'user'); if (user) { - return user.get('stripeConnectSubscriptions').then((subscriptions) => { + return get(user, 'stripeConnectSubscriptions').then((subscriptions) => { let subscription = subscriptions.find((subscription) => { return subscription.belongsTo('project').id() === project.id; }); diff --git a/app/styles/_alerts.scss b/app/styles/_alerts.scss index 2ad70d02a..3670458f0 100644 --- a/app/styles/_alerts.scss +++ b/app/styles/_alerts.scss @@ -12,7 +12,7 @@ // regular flash message full-width-container, displayed full width // almost on top of the page .full-width-container { - margin: 0 -10px 10px; + margin: -1px -10px 10px; padding: 5px 10px 5px 35px; } diff --git a/app/styles/layout/_header.scss b/app/styles/layout/_header.scss index ae7da46a6..4e9c05125 100644 --- a/app/styles/layout/_header.scss +++ b/app/styles/layout/_header.scss @@ -22,8 +22,9 @@ .header__logo { display: flex; align-items: center; - line-height: 50px; + line-height: 45px; margin: 0; + min-height: 45px; a { @include sprite($logo-small); display: inline-block; @@ -88,8 +89,12 @@ margin-left: auto; } +.onboarding__continue { + padding: 7px 0; +} + .onboarding__progress { - padding: 23px 0 22px 0; + padding: 18px 0 17px 0; width: 100px; .progress-bar-container { @@ -98,5 +103,5 @@ } .onboarding__steps { - padding: 16px 30px; + padding: 12px 0; } diff --git a/app/templates/components/create-comment-form.hbs b/app/templates/components/create-comment-form.hbs index e9f525090..a59272e27 100644 --- a/app/templates/components/create-comment-form.hbs +++ b/app/templates/components/create-comment-form.hbs @@ -25,7 +25,7 @@ {{else}}

- {{#link-to 'signup' class='button default small'}}Sign up for free{{/link-to}} to comment on this conversation, or {{#link-to 'login'}}sign in{{/link-to}}. + {{#link-to "signup" class='button default small'}}Sign up for free{{/link-to}} to comment on this conversation, or {{#link-to 'login'}}sign in{{/link-to}}.

{{/if}} diff --git a/app/templates/components/navigation-menu.hbs b/app/templates/components/navigation-menu.hbs index 88acf2d98..317a39791 100644 --- a/app/templates/components/navigation-menu.hbs +++ b/app/templates/components/navigation-menu.hbs @@ -10,7 +10,9 @@ {{#if navigationMenu.isOnboarding}}
-
Step {{onboarding.currentStepNumber}} of {{onboarding.totalSteps}}
+ {{#if navigationMenu.isViewingOnboarding}} +
Step {{onboarding.currentRouteStepNumber}} of {{onboarding.totalSteps}}
+ {{/if}}
{{/if}} @@ -28,7 +30,7 @@ {{else}} @@ -37,9 +39,17 @@ {{#if navigationMenu.isOnboarding}}
-
- {{progress-bar-container percentage=onboarding.progressPercentage}} -
+ {{#if navigationMenu.isViewingOnboarding}} +
+ {{progress-bar-container percentage=onboarding.progressPercentage}} +
+ {{/if}} + + {{#if (eq navigationMenu.currentRouteName "project.thank-you")}} +
+ {{link-to "Finish signing up" "start.hello" class="button default small"}} +
+ {{/if}}
{{/if}} diff --git a/app/templates/components/project-long-description.hbs b/app/templates/components/project-long-description.hbs index 035394d62..72893e58f 100644 --- a/app/templates/components/project-long-description.hbs +++ b/app/templates/components/project-long-description.hbs @@ -42,10 +42,11 @@ {{#if shouldDisplayEditor}}
{{editor-with-preview input=project.longDescriptionMarkdown isLoading=project.isSaving modifiedSubmit="save"}} - {{log project.errors.longDescriptionMarkdown}} + {{#each project.errors.longDescriptionMarkdown as |error|}}

{{error.message}}

{{/each}} +
diff --git a/app/templates/components/signup-form.hbs b/app/templates/components/signup-form.hbs index 8ed8e6ad9..14ce7816b 100644 --- a/app/templates/components/signup-form.hbs +++ b/app/templates/components/signup-form.hbs @@ -1,7 +1,7 @@
- {{#if (eq user.state 'signed_up_donating')}} + {{#if (eq user.signUpContext 'donation')}}

Join Code Corps to continue.

{{else}}

Join Code Corps today.

diff --git a/app/templates/components/thank-you-container.hbs b/app/templates/components/thank-you-container.hbs index a2b4e972e..841d6e9b3 100644 --- a/app/templates/components/thank-you-container.hbs +++ b/app/templates/components/thank-you-container.hbs @@ -7,6 +7,10 @@ From all the volunteers on the {{project.title}} team.

- {{link-to "Back to project" "project" project.organization.slug project.slug}} + {{#if onboarding.isOnboarding}} + {{link-to "Finish signing up" "start.hello" class="button default"}} + {{else}} + {{link-to "Back to project" "project" project.organization.slug project.slug class="button default"}} + {{/if}}

diff --git a/app/templates/index.hbs b/app/templates/index.hbs index 566491c3b..cd6bade09 100644 --- a/app/templates/index.hbs +++ b/app/templates/index.hbs @@ -5,7 +5,7 @@

Build a better future.

Contribute to software projects for {{typed-string strings=typedStrings typeSpeed=70 backDelay=1500 loop=true loopCount=false}}

- {{#link-to 'signup' class="button default large"}}Start Helping{{/link-to}} + {{#link-to "signup" class="button default large"}}Start Helping{{/link-to}}
@@ -29,7 +29,7 @@

Ready to get started?

- {{#link-to 'signup' class="button default large"}}Sign up now{{/link-to}} + {{#link-to "signup" class="button default large"}}Sign up now{{/link-to}}
diff --git a/mirage/config.js b/mirage/config.js index 1b5976c34..8f3c4794a 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -573,8 +573,8 @@ export default function() { this.get('/users', { coalesce: true }); this.post('/users', function(schema) { - let { email, password, username, state = 'signed_up' } = this.normalizedRequestAttrs(); - let user = schema.create('user', { email, password, state, username }); + let { email, password, username, state = 'signed_up', signUpContext } = this.normalizedRequestAttrs(); + let user = schema.create('user', { email, password, state, username, signUpContext }); schema.create('sluggedRoute', { slug: user.username, user }); return user; }); diff --git a/tests/acceptance/logout-test.js b/tests/acceptance/logout-test.js index aef210648..4878a908e 100644 --- a/tests/acceptance/logout-test.js +++ b/tests/acceptance/logout-test.js @@ -18,6 +18,6 @@ test('Logging out', function(assert) { indexPage.navMenu.userMenu.logOut(); }); andThen(function() { - assert.ok(indexPage.navMenu.loginLinkVisible, 'Page contains login link'); + assert.ok(indexPage.navMenu.signInLink.isVisible, 'Page contains login link'); }); }); diff --git a/tests/acceptance/navigation-test.js b/tests/acceptance/navigation-test.js index d73f156c1..ce31c5fc1 100644 --- a/tests/acceptance/navigation-test.js +++ b/tests/acceptance/navigation-test.js @@ -11,8 +11,8 @@ test('Logged out, can sign up', function(assert) { assert.expect(2); indexPage.visit(); andThen(function() { - assert.equal(indexPage.navMenu.signUp.text, 'Sign up', 'Page contains sign up link'); - indexPage.navMenu.signUp.click(); + assert.ok(indexPage.navMenu.signUpLink.isVisible, 'Page contains sign up link.'); + indexPage.navMenu.signUpLink.click(); }); andThen(function() { assert.ok(signupPage.form.isVisible, 'Page contains sign up form'); @@ -23,8 +23,8 @@ test('Logged out, can sign in', function(assert) { assert.expect(2); indexPage.visit(); andThen(function() { - assert.equal(indexPage.navMenu.logIn.text, 'Sign in', 'Page contains sign in link'); - indexPage.navMenu.logIn.click(); + assert.ok(indexPage.navMenu.signInLink.isVisible, 'Page contains sign in link.'); + indexPage.navMenu.signInLink.click(); }); andThen(function() { assert.ok(loginPage.form.isVisible, 'Page contains login form'); @@ -84,6 +84,6 @@ test('Logged in, from user menu can log out', function(assert) { indexPage.navMenu.userMenu.logOut(); }); andThen(function() { - assert.equal(indexPage.navMenu.logIn.text, 'Sign in', 'Page contains sign in link'); + assert.ok(indexPage.navMenu.signInLink.isVisible, 'Page contains sign in link.'); }); }); diff --git a/tests/acceptance/project-checkout-test.js b/tests/acceptance/project-checkout-test.js index f46362333..b5304aa42 100644 --- a/tests/acceptance/project-checkout-test.js +++ b/tests/acceptance/project-checkout-test.js @@ -134,7 +134,7 @@ test('Allows creating a card and donating (creating a subscription)', function(a }); test('Allows signing up and donating', function(assert) { - assert.expect(8); + assert.expect(9); stubStripe(this, stripeMockSuccess); @@ -160,7 +160,8 @@ test('Allows signing up and donating', function(assert) { andThen(() => { let user = server.schema.users.findBy({ email }); - assert.equal(user.state, 'signed_up_donating', 'User was created with state set properly.'); + assert.equal(user.state, 'signed_up', 'User was created with state set properly.'); + assert.equal(user.signUpContext, 'donation', 'User was created with context set properly.'); }); andThen(() => { diff --git a/tests/acceptance/project-donate-test.js b/tests/acceptance/project-donate-test.js index 1a6b56dc2..7de1b3263 100644 --- a/tests/acceptance/project-donate-test.js +++ b/tests/acceptance/project-donate-test.js @@ -74,7 +74,7 @@ test('Allows setting custom amount before continuing to checkout', function(asse }); test('Requires user to register before getting to checkout', function(assert) { - assert.expect(4); + assert.expect(5); let organization = server.create('organization'); let project = server.create('project', { organization }); @@ -104,7 +104,8 @@ test('Requires user to register before getting to checkout', function(assert) { andThen(() => { // check user was created let user = server.schema.users.findBy({ email }); - assert.equal(user.state, 'signed_up_donating', 'User was created with state set properly.'); + assert.equal(user.state, 'signed_up', 'User was created with state set properly.'); + assert.equal(user.signUpContext, 'donation', 'User was created with context set properly.'); // check we got redirected back assert.equal(currentRouteName(), 'project.checkout', 'User was redirected to checkout'); @@ -120,7 +121,7 @@ test('Requires user to register before getting to checkout', function(assert) { }); test('Requires user to register before getting to checkout, with custom amount', function(assert) { - assert.expect(4); + assert.expect(5); let organization = server.create('organization'); let project = server.create('project', { organization }); @@ -150,7 +151,8 @@ test('Requires user to register before getting to checkout, with custom amount', andThen(() => { // check user was created let user = server.schema.users.findBy({ email }); - assert.equal(user.state, 'signed_up_donating', 'User was created with state set properly.'); + assert.equal(user.state, 'signed_up', 'User was created with state set properly.'); + assert.equal(user.signUpContext, 'donation', 'User was created with context set properly.'); // check we got redirected back assert.equal(currentRouteName(), 'project.checkout', 'User was redirected to checkout'); diff --git a/tests/acceptance/signup-test.js b/tests/acceptance/signup-test.js index 27cb15f45..a9fd76c45 100644 --- a/tests/acceptance/signup-test.js +++ b/tests/acceptance/signup-test.js @@ -11,8 +11,8 @@ test('Signup form is accessible from the main site', function(assert) { indexPage.visit(); andThen(() => { - assert.ok(indexPage.navMenu.signUp.isVisible, 'Link to sign-up route is visible'); - indexPage.navMenu.signUp.click(); + assert.ok(indexPage.navMenu.signUpLink.isVisible, 'Link to sign-up route is visible'); + indexPage.navMenu.signUpLink.click(); }); andThen(() => { diff --git a/tests/integration/components/donations/donation-progress-test.js b/tests/integration/components/donations/donation-progress-test.js index 111700ac9..a43dcd4ea 100644 --- a/tests/integration/components/donations/donation-progress-test.js +++ b/tests/integration/components/donations/donation-progress-test.js @@ -29,7 +29,7 @@ test('it renders proper information', function(assert) { assert.equal(page.percentageLabel, 'of $1,000 goal', 'Correct percentage label is rendered'); assert.equal(page.percentageValue, '50%', 'Correct percentage value is rendered'); assert.equal(page.goalDescription, mockGoal.description, 'Goal description is rendered'); - assert.ok(page.rendersProgressBar, 'Progress bar component is rendered'); + assert.ok(page.progressBar.isVisible, 'Progress bar component is rendered'); }); test('it renders decimal values if there are any', function(assert) { @@ -44,5 +44,5 @@ test('it renders decimal values if there are any', function(assert) { assert.equal(page.amountValue, '$505.50', 'Correct amount is rendered'); assert.equal(page.percentageLabel, 'of $1,000 goal', 'Correct percentage label is rendered'); assert.equal(page.percentageValue, '50.5%', 'Correct percentage is rendered'); - assert.ok(page.rendersProgressBar, 'Progress bar component is rendered'); + assert.ok(page.progressBar.isVisible, 'Progress bar component is rendered'); }); diff --git a/tests/integration/components/navigation-menu-test.js b/tests/integration/components/navigation-menu-test.js index a8fabea0d..dc710e569 100644 --- a/tests/integration/components/navigation-menu-test.js +++ b/tests/integration/components/navigation-menu-test.js @@ -1,42 +1,112 @@ import { moduleForComponent, test } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; import stubService from 'code-corps-ember/tests/helpers/stub-service'; +import PageObject from 'ember-cli-page-object'; +import pageComponent from 'code-corps-ember/tests/pages/components/navigation-menu'; + +const page = PageObject.create(pageComponent); + +function renderPage() { + page.render(hbs`{{navigation-menu}}`); +} moduleForComponent('navigation-menu', 'Integration | Component | navigation menu', { - integration: true + integration: true, + beforeEach() { + page.setContext(this); + }, + afterEach() { + page.removeContext(); + } }); test('it renders elements for the default menu when logged out', function(assert) { - this.render(hbs`{{navigation-menu}}`); - assert.equal(this.$('.header__logo').length, 1); - assert.equal(this.$('.header-navigation__options').length, 2); - assert.equal(this.$('.user-menu').length, 0, 'does not show uer menu'); - assert.equal(this.$('.onboarding__steps').length, 0); + assert.expect(9); + + renderPage(); + + assert.ok(page.logo.isVisible, 'The logo is rendered.'); + assert.ok(page.projectsLink.isVisible, 'The link to projects route is rendered'); + assert.ok(page.blogLink.isVisible, 'The link to blogs route is rendered'); + assert.ok(page.signUpLink.isVisible, 'The link to signup route is rendered'); + assert.ok(page.signInLink.isVisible, 'The link to login route is rendered'); + assert.notOk(page.userMenu.isVisible, 'User menu is not shown.'); + assert.notOk(page.onboarding.status.isVisible, 'The onboarding status text is not rendered.'); + assert.notOk(page.onboarding.progressBar.isVisible, 'The onboarding progress bar is not rendered.'); + assert.notOk(page.onboarding.finishSigningUp.isVisible, 'The link to finish signing up is not rendered.'); }); test('it renders elements for the default menu when logged in', function(assert) { + assert.expect(9); + stubService(this, 'session', { isAuthenticated: true }); - this.render(hbs`{{navigation-menu}}`); - assert.equal(this.$('.header__logo').length, 1); - assert.equal(this.$('.header-navigation__options').length, 2); - assert.equal(this.$('.user-menu').length, 1, 'shows uer menu'); - assert.equal(this.$('.onboarding__steps').length, 0); + renderPage(); + + assert.ok(page.logo.isVisible, 'The logo is rendered.'); + assert.ok(page.projectsLink.isVisible, 'The link to projects route is rendered'); + assert.ok(page.blogLink.isVisible, 'The link to blogs route is rendered'); + assert.notOk(page.signUpLink.isVisible, 'The link to signup route is rendered'); + assert.notOk(page.signInLink.isVisible, 'The link to login route is rendered'); + assert.ok(page.userMenu.isVisible, 'User menu is shown.'); + assert.notOk(page.onboarding.status.isVisible, 'The onboarding status text is not rendered.'); + assert.notOk(page.onboarding.progressBar.isVisible, 'The onboarding progress bar is not rendered.'); + assert.notOk(page.onboarding.finishSigningUp.isVisible, 'The link to finish signing up is not rendered.'); }); -test('it renders elements for the onboarding menu', function(assert) { - stubService(this, 'navigation-menu', { isOnboarding: true }); +test('it renders elements for the onboarding menu correctly when on onboarding route', function(assert) { + assert.expect(11); + + stubService(this, 'navigation-menu', { + isOnboarding: true, + isViewingOnboarding: true + }); + stubService(this, 'onboarding', { - currentStepNumber: 1, + currentRouteStepNumber: 1, totalSteps: 4, progressPercentage: 25 }); - this.render(hbs`{{navigation-menu}}`); - assert.equal(this.$('.header__logo').length, 1); - assert.equal(this.$('.header-navigation__options').length, 0); - assert.equal(this.$('.user-menu').length, 0, 'does not show uer menu'); - assert.equal(this.$('.onboarding__steps').length, 1); - assert.equal(this.$('.onboarding__steps').text().trim(), 'Step 1 of 4'); - assert.equal(this.$('.progress-bar').attr('style'), 'width: 25%;'); + renderPage(); + + assert.ok(page.logo.isVisible, 'The logo is rendered.'); + assert.notOk(page.projectsLink.isVisible, 'The link to projects route is not rendered.'); + assert.notOk(page.blogLink.isVisible, 'The link to blogs route is not rendered.'); + + assert.notOk(page.userMenu.isVisible, 'User menu is not shown.'); + assert.notOk(page.signUpLink.isVisible, 'The link to signup route is rendered.'); + assert.notOk(page.signInLink.isVisible, 'The link to login route is rendered.'); + + assert.ok(page.onboarding.status.isVisible, 'The onboarding status text is rendered.'); + assert.equal(page.onboarding.status.text, 'Step 1 of 4', 'Correct status is rendered.'); + assert.ok(page.onboarding.progressBar.isVisible, 'The onboarding progress bar is rendered.'); + assert.ok(page.onboarding.progressBar.displaysPercentage(25), 'Correct progress percentage is rendered.'); + assert.notOk(page.onboarding.finishSigningUp.isVisible, 'The link to finish signing up is not rendered.'); +}); + +test('it renders elements for the onboarding menu correctly when on project.thank-you route', function(assert) { + assert.expect(9); + + stubService(this, 'navigation-menu', { + // on project.thank-you route + currentRouteName: 'project.thank-you', + isOnboarding: true, + // not on nonboarding route + isViewingOnboarding: false + }); + + renderPage(); + + assert.ok(page.logo.isVisible, 'The logo is rendered.'); + assert.notOk(page.projectsLink.isVisible, 'The link to projects route is not rendered'); + assert.notOk(page.blogLink.isVisible, 'The link to blogs route is not rendered'); + + assert.notOk(page.userMenu.isVisible, 'User menu is not shown.'); + assert.notOk(page.signUpLink.isVisible, 'The link to signup route is rendered'); + assert.notOk(page.signInLink.isVisible, 'The link to login route is rendered'); + + assert.notOk(page.onboarding.status.isVisible, 'Onboarding status is not rendered.'); + assert.notOk(page.onboarding.progressBar.isVisible, 'Onboarding progress bar is not rendered.'); + assert.ok(page.onboarding.finishSigningUp.isVisible, 'The link to finish signing up is rendered.'); }); diff --git a/tests/integration/components/signup-form-test.js b/tests/integration/components/signup-form-test.js index def85f9fa..2ef9e3443 100644 --- a/tests/integration/components/signup-form-test.js +++ b/tests/integration/components/signup-form-test.js @@ -38,8 +38,8 @@ test('renders different title if user is donating', function(assert) { renderPage(); - let normalUser = { state: null }; - let donatingUser = { state: 'signed_up_donating' }; + let normalUser = { signUpContext: null }; + let donatingUser = { signUpContext: 'donation' }; run(() => set(this, 'user', normalUser)); assert.equal(page.title.text, 'Join Code Corps today.', 'Title is correct.'); diff --git a/tests/pages/components/donations/donation-progress.js b/tests/pages/components/donations/donation-progress.js index cd98ebf76..9642ed1a6 100644 --- a/tests/pages/components/donations/donation-progress.js +++ b/tests/pages/components/donations/donation-progress.js @@ -1,4 +1,5 @@ -import { isVisible, text } from 'ember-cli-page-object'; +import { text } from 'ember-cli-page-object'; +import progressBar from 'code-corps-ember/tests/pages/components/progress-bar'; export default { scope: '.donation-progress', @@ -7,5 +8,5 @@ export default { goalDescription: text('.donation-progress__description'), percentageLabel: text('.donation-progress__details__percentage__label'), percentageValue: text('.donation-progress__details__percentage__value'), - rendersProgressBar: isVisible('.progress-bar') + progressBar }; diff --git a/tests/pages/components/navigation-menu.js b/tests/pages/components/navigation-menu.js index f17862b26..de96d0445 100644 --- a/tests/pages/components/navigation-menu.js +++ b/tests/pages/components/navigation-menu.js @@ -1,18 +1,46 @@ -import { isVisible } from 'ember-cli-page-object'; -import userMenu from './user-menu'; +import progressBar from 'code-corps-ember/tests/pages/components/progress-bar'; +import userMenu from 'code-corps-ember/tests/pages/components/user-menu'; export default { - loginLinkVisible: isVisible('a.login'), - + // logo logo: { scope: '.header__logo a' }, - logIn: { - scope: 'a.login' + + // navigation + projectsLink: { + scope: '.header-navigation__options li a:contains("Projects")' + }, + + blogLink: { + scope: '.header-navigation__options li a:contains("Blog")' }, - signUp: { - scope: 'a.signup' + + signInLink: { + scope: '.header-navigation__options li a:contains("Sign in")' }, - userMenu + signUpLink: { + scope: '.header-navigation__options li a:contains("Sign up")' + }, + + // user menu + userMenu, + + // onboarding + + onboarding: { + // status text + status: { + scope: '.onboarding__steps' + }, + + // progress bar + progressBar, + + // link to finish signing up + finishSigningUp: { + scope: '.onboarding__continue a' + } + } }; diff --git a/tests/pages/oauth/stripe.js b/tests/pages/oauth/stripe.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/unit/mixins/onboarding-route-test.js b/tests/unit/mixins/onboarding-route-test.js deleted file mode 100644 index 2b15c6ce5..000000000 --- a/tests/unit/mixins/onboarding-route-test.js +++ /dev/null @@ -1,14 +0,0 @@ -import Ember from 'ember'; -import OnboardingRouteMixin from 'code-corps-ember/mixins/onboarding-route'; -import { module, test } from 'qunit'; - -const { Object } = Ember; - -module('Unit | Mixin | onboarding route'); - -// Replace this with your real tests. -test('it works', function(assert) { - let OnboardingRouteObject = Object.extend(OnboardingRouteMixin); - let subject = OnboardingRouteObject.create(); - assert.ok(subject); -}); diff --git a/tests/unit/models/user-test.js b/tests/unit/models/user-test.js index dd0482dd0..66298360b 100644 --- a/tests/unit/models/user-test.js +++ b/tests/unit/models/user-test.js @@ -23,7 +23,8 @@ test('it exists', function(assert) { testForAttributes('user', [ 'biography', 'cloudinaryPublicId', 'email', 'firstName', 'insertedAt', 'lastName', 'name', 'password', 'photoLargeUrl', 'photoThumbUrl', - 'state', 'stateTransition', 'twitter', 'username', 'website' + 'signUpContext', 'state', 'stateTransition', 'twitter', 'username', + 'website' ]); testForBelongsTo('user', 'stripePlatformCard'); diff --git a/tests/unit/services/onboarding-test.js b/tests/unit/services/onboarding-test.js index bdfd1d0ce..4a77bf571 100644 --- a/tests/unit/services/onboarding-test.js +++ b/tests/unit/services/onboarding-test.js @@ -1,7 +1,7 @@ import { moduleFor, test } from 'ember-qunit'; import Ember from 'ember'; -const { isPresent } = Ember; +const { get, isPresent } = Ember; moduleFor('service:onboarding', 'Unit | Service | onboarding', { // Specify the other units that are required for this test. @@ -10,8 +10,8 @@ moduleFor('service:onboarding', 'Unit | Service | onboarding', { test('it has number, state, currentRoute, and nextRoute defined in each step', function(assert) { let service = this.subject(); - let steps = service.get('_steps'); - let totalSteps = service.get('totalSteps'); + let steps = get(service, '_steps'); + let totalSteps = get(service, 'totalSteps'); let numberOfKeys = 5; assert.expect(totalSteps * numberOfKeys); @@ -19,7 +19,7 @@ test('it has number, state, currentRoute, and nextRoute defined in each step', f for (let i = 0; i < totalSteps; i++) { assert.ok(isPresent(steps[i].number)); assert.ok(isPresent(steps[i].state)); - assert.ok(isPresent(steps[i].currentRoute)); + assert.ok(isPresent(steps[i].route)); assert.ok(isPresent(steps[i].nextRoute)); assert.ok(isPresent(steps[i].nextStateTransition)); } @@ -33,18 +33,16 @@ test('it returns the number of steps', function(assert) { } } }); - assert.equal(service.get('totalSteps'), 4); + assert.equal(get(service, 'totalSteps'), 4); }); test('it returns the current step number', function(assert) { let service = this.subject({ - currentUser: { - user: { - state: 'signed_up' - } + routing: { + currentRouteName: 'start.hello' } }); - assert.equal(service.get('currentStepNumber'), 1); + assert.equal(get(service, 'currentRouteStepNumber'), 1); }); test('it returns the current step state', function(assert) { @@ -55,7 +53,7 @@ test('it returns the current step state', function(assert) { } } }); - assert.equal(service.get('currentStepState'), 'signed_up'); + assert.equal(get(service, 'currentStepState'), 'signed_up'); }); test('it computes states', function(assert) { @@ -67,10 +65,10 @@ test('it computes states', function(assert) { } } }); - assert.ok(service.get('isEditingProfile')); - assert.notOk(service.get('isSelectingCategories')); - assert.notOk(service.get('isSelectingRoles')); - assert.notOk(service.get('isSelectingSkills')); + assert.ok(get(service, 'shouldEditProfile')); + assert.notOk(get(service, 'shouldSelectCategories')); + assert.notOk(get(service, 'shouldSelectRoles')); + assert.notOk(get(service, 'shouldSelectSkills')); }); test('it knows when the user is onboarding', function(assert) { @@ -81,7 +79,7 @@ test('it knows when the user is onboarding', function(assert) { } } }); - assert.ok(service.get('isOnboarding')); + assert.ok(get(service, 'isOnboarding')); }); test('it knows when the user is not onboarding', function(assert) { @@ -92,40 +90,34 @@ test('it knows when the user is not onboarding', function(assert) { } } }); - assert.notOk(service.get('isOnboarding')); + assert.notOk(get(service, 'isOnboarding')); }); test('it knows the progress percentage', function(assert) { let service = this.subject({ - currentUser: { - user: { - state: 'signed_up' - } + routing: { + currentRouteName: 'start.hello' } }); - assert.equal(service.get('progressPercentage'), 25); + assert.equal(get(service, 'progressPercentage'), 25); }); test('it knows the current route', function(assert) { let service = this.subject({ - currentUser: { - user: { - state: 'signed_up' - } + routing: { + currentRouteName: 'start.hello' } }); - assert.equal(service.get('currentRoute'), 'start.hello'); + assert.equal(get(service, 'currentRouteName'), 'start.hello'); }); test('it knows the next route', function(assert) { let service = this.subject({ - currentUser: { - user: { - state: 'signed_up' - } + routing: { + currentRouteName: 'start.hello' } }); - assert.equal(service.get('nextRoute'), 'start.interests'); + assert.equal(get(service, 'nextRoute'), 'start.interests'); }); test('it knows the next state transition', function(assert) { @@ -136,18 +128,5 @@ test('it knows the next state transition', function(assert) { } } }); - assert.equal(service.get('nextStateTransition'), 'edit_profile'); -}); - -test('it knows the onboarding routes', function(assert) { - let service = this.subject(); - let steps = service.get('_steps'); - let totalSteps = service.get('totalSteps'); - let routes = service.get('routes'); - - assert.expect(totalSteps); - - for (let i = 0; i < totalSteps; i++) { - assert.ok(routes.includes(steps[i].currentRoute)); - } + assert.equal(get(service, 'nextStateTransition'), 'edit_profile'); }); diff --git a/yarn.lock b/yarn.lock index db6e5e715..d56872595 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3065,9 +3065,9 @@ ember-dragula@1.9.3: ember-cli-babel "^5.1.5" rsvp "^3.2.1" -ember-exam@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/ember-exam/-/ember-exam-0.6.0.tgz#665a5c14c80daeea0d85b1beb62b7f5c2e29d14f" +ember-exam@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/ember-exam/-/ember-exam-0.6.1.tgz#3e66fc97a51e0901535b3629941a7e42d96ea718" dependencies: chalk "^1.1.3" cli-table2 "^0.2.0" @@ -5846,9 +5846,9 @@ normalize-range@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" -normalize.css@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-4.2.0.tgz#21d66cc557154d4379fd1e079ec7de58a379b099" +normalize.css@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-6.0.0.tgz#22188c2707c911fb3ad3c1aac0677ff68661bea8" normalize.css@~4.1.1: version "4.1.1" @@ -7932,6 +7932,10 @@ yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" +yuidoc-ember-theme@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/yuidoc-ember-theme/-/yuidoc-ember-theme-1.3.0.tgz#920b20a8d3bb65ce880563a28ec28ed5ba744503" + zxcvbn@^4.3.0: version "4.4.2" resolved "https://registry.yarnpkg.com/zxcvbn/-/zxcvbn-4.4.2.tgz#28ec17cf09743edcab056ddd8b1b06262cc73c30"