Merge pull request #4918 from techAPJ/user-fields-invite
FEATURE: add required user fields to invite accept form
This commit is contained in:
commit
545c0ab056
|
@ -7,9 +7,10 @@ import InputValidation from 'discourse/models/input-validation';
|
||||||
import PasswordValidation from "discourse/mixins/password-validation";
|
import PasswordValidation from "discourse/mixins/password-validation";
|
||||||
import UsernameValidation from "discourse/mixins/username-validation";
|
import UsernameValidation from "discourse/mixins/username-validation";
|
||||||
import NameValidation from "discourse/mixins/name-validation";
|
import NameValidation from "discourse/mixins/name-validation";
|
||||||
|
import UserFieldsValidation from "discourse/mixins/user-fields-validation";
|
||||||
import { userPath } from 'discourse/lib/url';
|
import { userPath } from 'discourse/lib/url';
|
||||||
|
|
||||||
export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, UsernameValidation, NameValidation, {
|
export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, UsernameValidation, NameValidation, UserFieldsValidation, {
|
||||||
login: Ember.inject.controller(),
|
login: Ember.inject.controller(),
|
||||||
|
|
||||||
complete: false,
|
complete: false,
|
||||||
|
@ -50,19 +51,10 @@ export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, U
|
||||||
if (this.get('emailValidation.failed')) return true;
|
if (this.get('emailValidation.failed')) return true;
|
||||||
if (this.get('usernameValidation.failed')) return true;
|
if (this.get('usernameValidation.failed')) return true;
|
||||||
if (this.get('passwordValidation.failed')) return true;
|
if (this.get('passwordValidation.failed')) return true;
|
||||||
|
if (this.get('userFieldsValidation.failed')) return true;
|
||||||
|
|
||||||
// Validate required fields
|
|
||||||
let userFields = this.get('userFields');
|
|
||||||
if (userFields) { userFields = userFields.filterBy('field.required'); }
|
|
||||||
if (!Ember.isEmpty(userFields)) {
|
|
||||||
const anyEmpty = userFields.any(function(uf) {
|
|
||||||
const val = uf.get('value');
|
|
||||||
return !val || Ember.isEmpty(val);
|
|
||||||
});
|
|
||||||
if (anyEmpty) { return true; }
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}.property('passwordRequired', 'nameValidation.failed', 'emailValidation.failed', 'usernameValidation.failed', 'passwordValidation.failed', 'formSubmitted', 'userFields.@each.value'),
|
}.property('passwordRequired', 'nameValidation.failed', 'emailValidation.failed', 'usernameValidation.failed', 'passwordValidation.failed', 'userFieldsValidation.failed', 'formSubmitted'),
|
||||||
|
|
||||||
|
|
||||||
usernameRequired: Ember.computed.not('authOptions.omit_username'),
|
usernameRequired: Ember.computed.not('authOptions.omit_username'),
|
||||||
|
@ -82,10 +74,6 @@ export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, U
|
||||||
});
|
});
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
nameInstructions: function() {
|
|
||||||
return I18n.t(Discourse.SiteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions');
|
|
||||||
}.property(),
|
|
||||||
|
|
||||||
// Check the email address
|
// Check the email address
|
||||||
emailValidation: function() {
|
emailValidation: function() {
|
||||||
// If blank, fail without a reason
|
// If blank, fail without a reason
|
||||||
|
@ -212,18 +200,6 @@ export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, U
|
||||||
return self.flash(I18n.t('create_account.failed'), 'error');
|
return self.flash(I18n.t('create_account.failed'), 'error');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_createUserFields: function() {
|
|
||||||
if (!this.site) { return; }
|
|
||||||
|
|
||||||
let userFields = this.site.get('user_fields');
|
|
||||||
if (userFields) {
|
|
||||||
userFields = _.sortBy(userFields, 'position').map(function(f) {
|
|
||||||
return Ember.Object.create({ value: null, field: f });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.set('userFields', userFields);
|
|
||||||
}.on('init')
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,15 +5,17 @@ import { ajax } from 'discourse/lib/ajax';
|
||||||
import PasswordValidation from "discourse/mixins/password-validation";
|
import PasswordValidation from "discourse/mixins/password-validation";
|
||||||
import UsernameValidation from "discourse/mixins/username-validation";
|
import UsernameValidation from "discourse/mixins/username-validation";
|
||||||
import NameValidation from "discourse/mixins/name-validation";
|
import NameValidation from "discourse/mixins/name-validation";
|
||||||
|
import UserFieldsValidation from "discourse/mixins/user-fields-validation";
|
||||||
import { findAll as findLoginMethods } from 'discourse/models/login-method';
|
import { findAll as findLoginMethods } from 'discourse/models/login-method';
|
||||||
|
|
||||||
export default Ember.Controller.extend(PasswordValidation, UsernameValidation, NameValidation, {
|
export default Ember.Controller.extend(PasswordValidation, UsernameValidation, NameValidation, UserFieldsValidation, {
|
||||||
invitedBy: Ember.computed.alias('model.invited_by'),
|
invitedBy: Ember.computed.alias('model.invited_by'),
|
||||||
email: Ember.computed.alias('model.email'),
|
email: Ember.computed.alias('model.email'),
|
||||||
accountUsername: Ember.computed.alias('model.username'),
|
accountUsername: Ember.computed.alias('model.username'),
|
||||||
passwordRequired: Ember.computed.notEmpty('accountPassword'),
|
passwordRequired: Ember.computed.notEmpty('accountPassword'),
|
||||||
successMessage: null,
|
successMessage: null,
|
||||||
errorMessage: null,
|
errorMessage: null,
|
||||||
|
userFields: null,
|
||||||
inviteImageUrl: getUrl('/images/envelope.svg'),
|
inviteImageUrl: getUrl('/images/envelope.svg'),
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
|
@ -21,11 +23,6 @@ export default Ember.Controller.extend(PasswordValidation, UsernameValidation, N
|
||||||
return I18n.t('invites.welcome_to', {site_name: this.siteSettings.title});
|
return I18n.t('invites.welcome_to', {site_name: this.siteSettings.title});
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed
|
|
||||||
nameLabel() {
|
|
||||||
return I18n.t(this.siteSettings.full_name_required ? 'invites.name_label' : 'invites.name_label_optional');
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('email')
|
@computed('email')
|
||||||
yourEmailMessage(email) {
|
yourEmailMessage(email) {
|
||||||
return I18n.t('invites.your_email', {email: email});
|
return I18n.t('invites.your_email', {email: email});
|
||||||
|
@ -36,20 +33,30 @@ export default Ember.Controller.extend(PasswordValidation, UsernameValidation, N
|
||||||
return findLoginMethods(this.siteSettings, this.capabilities, this.site.isMobileDevice).length > 0;
|
return findLoginMethods(this.siteSettings, this.capabilities, this.site.isMobileDevice).length > 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('usernameValidation.failed', 'passwordValidation.failed', 'nameValidation.failed')
|
@computed('usernameValidation.failed', 'passwordValidation.failed', 'nameValidation.failed', 'userFieldsValidation.failed')
|
||||||
submitDisabled(usernameFailed, passwordFailed, nameFailed) {
|
submitDisabled(usernameFailed, passwordFailed, nameFailed, userFieldsFailed) {
|
||||||
return usernameFailed || passwordFailed || nameFailed;
|
return usernameFailed || passwordFailed || nameFailed || userFieldsFailed;
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
submit() {
|
submit() {
|
||||||
|
|
||||||
|
const userFields = this.get('userFields');
|
||||||
|
let userCustomFields = {};
|
||||||
|
if (!Ember.isEmpty(userFields)) {
|
||||||
|
userFields.forEach(function(f) {
|
||||||
|
userCustomFields[f.get('field.id')] = f.get('value');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ajax({
|
ajax({
|
||||||
url: `/invites/show/${this.get('model.token')}.json`,
|
url: `/invites/show/${this.get('model.token')}.json`,
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
data: {
|
data: {
|
||||||
username: this.get('accountUsername'),
|
username: this.get('accountUsername'),
|
||||||
name: this.get('accountName'),
|
name: this.get('accountName'),
|
||||||
password: this.get('accountPassword')
|
password: this.get('accountPassword'),
|
||||||
|
userCustomFields
|
||||||
}
|
}
|
||||||
}).then(result => {
|
}).then(result => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
|
|
@ -3,6 +3,11 @@ import { default as computed } from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
export default Ember.Mixin.create({
|
export default Ember.Mixin.create({
|
||||||
|
|
||||||
|
@computed()
|
||||||
|
nameInstructions() {
|
||||||
|
return I18n.t(this.siteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions');
|
||||||
|
},
|
||||||
|
|
||||||
// Validate the name.
|
// Validate the name.
|
||||||
@computed('accountName')
|
@computed('accountName')
|
||||||
nameValidation() {
|
nameValidation() {
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import InputValidation from 'discourse/models/input-validation';
|
||||||
|
import { on, default as computed } from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
|
export default Ember.Mixin.create({
|
||||||
|
|
||||||
|
@on('init')
|
||||||
|
_createUserFields() {
|
||||||
|
if (!this.site) { return; }
|
||||||
|
|
||||||
|
let userFields = this.site.get('user_fields');
|
||||||
|
if (userFields) {
|
||||||
|
userFields = _.sortBy(userFields, 'position').map(function(f) {
|
||||||
|
return Ember.Object.create({ value: null, field: f });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.set('userFields', userFields);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
@computed('userFields.@each.value')
|
||||||
|
userFieldsValidation() {
|
||||||
|
let userFields = this.get('userFields');
|
||||||
|
if (userFields) { userFields = userFields.filterBy('field.required'); }
|
||||||
|
if (!Ember.isEmpty(userFields)) {
|
||||||
|
const anyEmpty = userFields.any(uf => {
|
||||||
|
const val = uf.get('value');
|
||||||
|
return !val || Ember.isEmpty(val);
|
||||||
|
});
|
||||||
|
if (anyEmpty) {
|
||||||
|
return InputValidation.create({ failed: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InputValidation.create({ ok: true });
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,3 +1,3 @@
|
||||||
<div class='controls'>
|
<div class='controls'>
|
||||||
<label class="control-label">{{input checked=value type="checkbox"}} {{{field.description}}}</label>
|
<label class="control-label checkbox-label">{{input checked=value type="checkbox"}} {{{field.description}}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -23,26 +23,36 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form>
|
<form>
|
||||||
<label>{{i18n 'user.username.title'}}</label>
|
|
||||||
<div class="input username-input">
|
<div class="input username-input">
|
||||||
|
<label>{{i18n 'user.username.title'}}</label>
|
||||||
{{input value=accountUsername id="new-account-username" name="username" maxlength=maxUsernameLength autocomplete="off"}}
|
{{input value=accountUsername id="new-account-username" name="username" maxlength=maxUsernameLength autocomplete="off"}}
|
||||||
{{input-tip validation=usernameValidation id="username-validation"}}
|
{{input-tip validation=usernameValidation id="username-validation"}}
|
||||||
|
<div class="instructions">{{i18n 'user.username.instructions'}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label>{{nameLabel}}</label>
|
|
||||||
<div class="input name-input">
|
<div class="input name-input">
|
||||||
|
<label>{{i18n 'invites.name_label'}}</label>
|
||||||
{{input value=accountName id="new-account-name" name="name"}}
|
{{input value=accountName id="new-account-name" name="name"}}
|
||||||
|
<div class="instructions">{{nameInstructions}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label>{{i18n 'invites.password_label'}}</label>
|
|
||||||
<div class="input password-input">
|
<div class="input password-input">
|
||||||
|
<label>{{i18n 'invites.password_label'}}</label>
|
||||||
{{password-field value=accountPassword type="password" id="new-account-password" capsLockOn=capsLockOn}}
|
{{password-field value=accountPassword type="password" id="new-account-password" capsLockOn=capsLockOn}}
|
||||||
{{input-tip validation=passwordValidation}}
|
{{input-tip validation=passwordValidation}}
|
||||||
|
<div class="instructions">
|
||||||
|
{{passwordInstructions}}
|
||||||
|
<div class="caps-lock-warning {{unless capsLockOn 'invisible'}}"><i class="fa fa-exclamation-triangle"></i> {{i18n 'login.caps_lock_warning'}}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="instructions">
|
{{#if userFields}}
|
||||||
<div class="caps-lock-warning {{unless capsLockOn 'invisible'}}"><i class="fa fa-exclamation-triangle"></i> {{i18n 'login.caps_lock_warning'}}</div>
|
<div class='user-fields'>
|
||||||
</div>
|
{{#each userFields as |f|}}
|
||||||
|
{{user-field field=f.field value=f.value}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<button class='btn btn-primary' {{action "submit"}} disabled={{submitDisabled}}>{{i18n 'invites.accept_invite'}}</button>
|
<button class='btn btn-primary' {{action "submit"}} disabled={{submitDisabled}}>{{i18n 'invites.accept_invite'}}</button>
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,13 @@ $input-width: 220px;
|
||||||
label {
|
label {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
.instructions {
|
||||||
|
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.929em;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
form {
|
form {
|
||||||
label, .input {
|
.controls, .input {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
},
|
||||||
|
input, label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
},
|
||||||
|
.user-field .control-label:not(.checkbox-label) {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,12 @@ class InvitesController < ApplicationController
|
||||||
|
|
||||||
def perform_accept_invitation
|
def perform_accept_invitation
|
||||||
params.require(:id)
|
params.require(:id)
|
||||||
params.permit(:username, :name, :password)
|
params.permit(:username, :name, :password, :user_custom_fields)
|
||||||
invite = Invite.find_by(invite_key: params[:id])
|
invite = Invite.find_by(invite_key: params[:id])
|
||||||
|
|
||||||
if invite.present?
|
if invite.present?
|
||||||
begin
|
begin
|
||||||
user = invite.redeem(username: params[:username], name: params[:name], password: params[:password])
|
user = invite.redeem(username: params[:username], name: params[:name], password: params[:password], user_custom_fields: params[:user_custom_fields])
|
||||||
if user.present?
|
if user.present?
|
||||||
log_on_user(user)
|
log_on_user(user)
|
||||||
post_process_invite(user)
|
post_process_invite(user)
|
||||||
|
|
|
@ -52,8 +52,8 @@ class Invite < ActiveRecord::Base
|
||||||
invalidated_at.nil?
|
invalidated_at.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def redeem(username: nil, name: nil, password: nil)
|
def redeem(username: nil, name: nil, password: nil, user_custom_fields: nil)
|
||||||
InviteRedeemer.new(self, username, name, password).redeem unless expired? || destroyed? || !link_valid?
|
InviteRedeemer.new(self, username, name, password, user_custom_fields).redeem unless expired? || destroyed? || !link_valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.extend_permissions(topic, user, invited_by)
|
def self.extend_permissions(topic, user, invited_by)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
InviteRedeemer = Struct.new(:invite, :username, :name, :password) do
|
InviteRedeemer = Struct.new(:invite, :username, :name, :password, :user_custom_fields) do
|
||||||
|
|
||||||
def redeem
|
def redeem
|
||||||
Invite.transaction do
|
Invite.transaction do
|
||||||
|
@ -18,7 +18,7 @@ InviteRedeemer = Struct.new(:invite, :username, :name, :password) do
|
||||||
end
|
end
|
||||||
|
|
||||||
# extracted from User cause it is very specific to invites
|
# extracted from User cause it is very specific to invites
|
||||||
def self.create_user_from_invite(invite, username, name, password=nil)
|
def self.create_user_from_invite(invite, username, name, password=nil, user_custom_fields=nil)
|
||||||
user_exists = User.find_by_email(invite.email)
|
user_exists = User.find_by_email(invite.email)
|
||||||
return user if user_exists
|
return user if user_exists
|
||||||
|
|
||||||
|
@ -42,6 +42,18 @@ InviteRedeemer = Struct.new(:invite, :username, :name, :password) do
|
||||||
user.approved_at = Time.zone.now
|
user.approved_at = Time.zone.now
|
||||||
end
|
end
|
||||||
|
|
||||||
|
user_fields = UserField.all
|
||||||
|
if user_custom_fields.present? && user_fields.present?
|
||||||
|
field_params = user_custom_fields || {}
|
||||||
|
fields = user.custom_fields
|
||||||
|
|
||||||
|
user_fields.each do |f|
|
||||||
|
field_val = field_params[f.id.to_s]
|
||||||
|
fields["user_field_#{f.id}"] = field_val[0...UserField.max_length] unless field_val.blank?
|
||||||
|
end
|
||||||
|
user.custom_fields = fields
|
||||||
|
end
|
||||||
|
|
||||||
user.moderator = true if invite.moderator? && invite.invited_by.staff?
|
user.moderator = true if invite.moderator? && invite.invited_by.staff?
|
||||||
user.save!
|
user.save!
|
||||||
|
|
||||||
|
@ -76,7 +88,7 @@ InviteRedeemer = Struct.new(:invite, :username, :name, :password) do
|
||||||
|
|
||||||
def get_invited_user
|
def get_invited_user
|
||||||
result = get_existing_user
|
result = get_existing_user
|
||||||
result ||= InviteRedeemer.create_user_from_invite(invite, username, name, password)
|
result ||= InviteRedeemer.create_user_from_invite(invite, username, name, password, user_custom_fields)
|
||||||
result.send_welcome_message = false
|
result.send_welcome_message = false
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
|
@ -1101,7 +1101,6 @@ en:
|
||||||
accept_invite: "Accept Invitation"
|
accept_invite: "Accept Invitation"
|
||||||
success: "Your account has been created and you're now logged in."
|
success: "Your account has been created and you're now logged in."
|
||||||
name_label: "Name"
|
name_label: "Name"
|
||||||
name_label_optional: "Name (optional)"
|
|
||||||
password_label: "Set Password (optional)"
|
password_label: "Set Password (optional)"
|
||||||
|
|
||||||
password_reset:
|
password_reset:
|
||||||
|
|
|
@ -93,5 +93,19 @@ describe InviteRedeemer do
|
||||||
expect(user.confirm_password?(password)).to eq(true)
|
expect(user.confirm_password?(password)).to eq(true)
|
||||||
expect(user.approved).to eq(true)
|
expect(user.approved).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can set custom fields" do
|
||||||
|
required_field = Fabricate(:user_field)
|
||||||
|
optional_field= Fabricate(:user_field, required: false)
|
||||||
|
user_fields = {
|
||||||
|
required_field.id.to_s => 'value1',
|
||||||
|
optional_field.id.to_s => 'value2'
|
||||||
|
}
|
||||||
|
user = InviteRedeemer.new(invite, username, name, password, user_fields).redeem
|
||||||
|
|
||||||
|
expect(user).to be_present
|
||||||
|
expect(user.custom_fields["user_field_#{required_field.id}"]).to eq('value1')
|
||||||
|
expect(user.custom_fields["user_field_#{optional_field.id}"]).to eq('value2')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { acceptance } from "helpers/qunit-helpers";
|
||||||
|
|
||||||
|
acceptance("Accept Invite - User Fields", {
|
||||||
|
site: {
|
||||||
|
user_fields: [{"id":34,"name":"I've read the terms of service","field_type":"confirm","required":true},
|
||||||
|
{"id":35,"name":"What is your pet's name?","field_type":"text","required":true},
|
||||||
|
{"id":36,"name":"What's your dad like?","field_type":"text","required":false}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("accept invite with user fields", () => {
|
||||||
|
visit("/invites/myvalidinvitetoken");
|
||||||
|
andThen(() => {
|
||||||
|
ok(exists(".invites-show"), "shows the accept invite page");
|
||||||
|
ok(exists('.user-field'), "it has at least one user field");
|
||||||
|
ok(exists('.invites-show .btn-primary:disabled'), 'submit is disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
fillIn("#new-account-name", 'John Doe');
|
||||||
|
fillIn("#new-account-username", 'validname');
|
||||||
|
fillIn("#new-account-password", 'secur3ty4Y0uAndMe');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
ok(exists(".username-input .good"), "username is valid");
|
||||||
|
ok(exists('.invites-show .btn-primary:disabled'), 'submit is still disabled due to lack of user fields');
|
||||||
|
});
|
||||||
|
|
||||||
|
fillIn(".user-field input[type=text]:first", "Barky");
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
ok(exists('.invites-show .btn-primary:disabled'), 'submit is disabled because field is not checked');
|
||||||
|
});
|
||||||
|
|
||||||
|
click(".user-field input[type=checkbox]");
|
||||||
|
andThen(() => {
|
||||||
|
not(exists('.invites-show .btn-primary:disabled'), 'submit is enabled because field is checked');
|
||||||
|
});
|
||||||
|
|
||||||
|
click(".user-field input[type=checkbox]");
|
||||||
|
andThen(() => {
|
||||||
|
ok(exists('.invites-show .btn-primary:disabled'), 'unclicking the checkbox disables the submit');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue