Repository: solid/community-server
Pull request #877 (2021-07-29 15:59:48)

Make registration form self-explanatory
This is a redesign for the registration form so it is easier to understand what the different options are and how they interact.

RubenVerborgh: So weird, the tests were running locally!
joachimvh: > 
> 
> So weird, the tests were running locally!

Having another look, some tests are failing due to server errors, but some seem to also be failing because the template is not valid ejs: https://github.com/solid/community-server/pull/877/checks?check_run_id=3193790252#step:9:298 so even weirder.
RubenVerborgh: > not valid ejs

Probably I'm using language features of Node 16 that 12 does not have yet.

Patch:
diff --git a/src/identity/interaction/email-password/EmailPasswordUtil.ts b/src/identity/interaction/email-password/EmailPasswordUtil.ts
index 467374794..7ace30de0 100644
--- a/src/identity/interaction/email-password/EmailPasswordUtil.ts
+++ b/src/identity/interaction/email-password/EmailPasswordUtil.ts
@@ -31,13 +31,16 @@ export function throwIdpInteractionError(error: unknown, prefilled: Record<strin
  * @param confirmPassword - Confirmation of password to match.
  */
 export function assertPassword(password: any, confirmPassword: any): asserts password is string {
-  assert(typeof password === 'string' && password.length > 0, 'Password required');
+  assert(
+    typeof password === 'string' && password.length > 0,
+    'Please enter a password.',
+  );
   assert(
     typeof confirmPassword === 'string' && confirmPassword.length > 0,
-    'Password confirmation required',
+    'Please confirm your password.',
   );
   assert(
     password === confirmPassword,
-    'Password and confirmation do not match',
+    'Your password and confirmation did not match.',
   );
 }
diff --git a/src/identity/interaction/email-password/handler/RegistrationHandler.ts b/src/identity/interaction/email-password/handler/RegistrationHandler.ts
index 0b125752d..5199bf7aa 100644
--- a/src/identity/interaction/email-password/handler/RegistrationHandler.ts
+++ b/src/identity/interaction/email-password/handler/RegistrationHandler.ts
@@ -193,14 +193,12 @@ export class RegistrationHandler extends HttpHandler {
    */
   private async parseInput(request: HttpRequest): Promise<ParsedInput> {
     const parsed = await getFormDataRequestBody(request);
-    let prefilled: Record<string, string> = {};
+    const prefilled: Record<string, string> = {};
     try {
-      for (const key of Object.keys(parsed)) {
-        if (Array.isArray(parsed[key])) {
-          throw new Error(`Multiple values found for key ${key}`);
-        }
+      for (const [ key, value ] of Object.entries(parsed)) {
+        assert(!Array.isArray(value), `Unexpected multiple values for ${key}.`);
+        prefilled[key] = value ? value.trim() : '';
       }
-      prefilled = parsed as Record<string, string>;
       return this.validateInput(prefilled);
     } catch (err: unknown) {
       throwIdpInteractionError(err, prefilled);
@@ -212,54 +210,38 @@ export class RegistrationHandler extends HttpHandler {
    * Verifies that all the data combinations make sense.
    */
   private validateInput(parsed: NodeJS.Dict<string>): ParsedInput {
-    const { email, password, confirmPassword, podName, webId, template, createWebId, register, createPod } = parsed;
+    const { email, password, confirmPassword, webId, podName, register, createPod, createWebId, template } = parsed;
 
-    assert(typeof email === 'string' && email.length > 0 && emailRegex.test(email),
-      'A valid e-mail address is required');
+    // Parse email
+    assert(typeof email === 'string' && emailRegex.test(email), 'Please enter a valid e-mail address.');
 
-    const result: ParsedInput = {
+    const validated: ParsedInput = {
       email,
       template,
+      register: Boolean(register) || Boolean(createWebId),
+      createPod: Boolean(createPod) || Boolean(createWebId),
       createWebId: Boolean(createWebId),
-      register: Boolean(register),
-      createPod: Boolean(createPod),
     };
+    assert(validated.register || validated.createPod, 'Please register for a WebID or create a Pod.');
 
-    const validWebId = typeof webId === 'string' && webId.length > 0;
-    if (result.createWebId) {
-      if (validWebId) {
-        throw new Error('A WebID should only be provided when no new one is being created');
-      }
-    } else {
-      if (!validWebId) {
-        throw new Error('A WebID is required if no new one is being created');
-      }
-      result.webId = webId;
+    // Parse WebID
+    if (!validated.createWebId) {
+      assert(typeof webId === 'string' && /^https?:\/\/[^/]+/u.test(webId), 'Please enter a valid WebID.');
+      validated.webId = webId;
     }
 
-    if (result.register) {
-      assertPassword(password, confirmPassword);
-      result.password = password;
-    } else if (typeof password === 'string' && password.length > 0) {
-      throw new Error('A password should only be provided when registering');
+    // Parse Pod name
+    if (validated.createWebId || validated.createPod) {
+      assert(typeof podName === 'string' && podName.length > 0, 'Please specify a Pod name.');
+      validated.podName = podName;
     }
 
-    if (result.createWebId || result.createPod) {
-      assert(typeof podName === 'string' && podName.length > 0,
-        'A pod name is required when creating a pod and/or WebID');
-      result.podName = podName;
-    } else if (typeof podName === 'string' && podName.length > 0) {
-      throw new Error('A pod name should only be provided when creating a pod and/or WebID');
-    }
-
-    if (result.createWebId && !(result.register && result.createPod)) {
-      throw new Error('Creating a WebID is only possible when also registering and creating a pod');
-    }
-
-    if (!result.createWebId && !result.register && !result.createPod) {
-      throw new Error('At least one option needs to be chosen');
+    // Parse account
+    if (validated.register) {
+      assertPassword(password, confirmPassword);
+      validated.password = password;
     }
 
-    return result;
+    return validated;
   }
 }
diff --git a/templates/identity/email-password/login.html.ejs b/templates/identity/email-password/login.html.ejs
index 3588e4146..75b9b4a7b 100644
--- a/templates/identity/email-password/login.html.ejs
+++ b/templates/identity/email-password/login.html.ejs
@@ -19,6 +19,7 @@
       <% } %>
 
       <fieldset>
+        <legend>Your account</legend>
         <ol>
           <li>
             <label for="email">Email</label>
@@ -29,7 +30,7 @@
             <input id="password" type="password" name="password">
           </li>
           <li class="checkbox">
-            <label><input type="checkbox" name="remember" value="yes" checked>Stay signed in</label>
+            <label><input type="checkbox" name="remember" value="yes" checked>Stay logged in</label>
           </li>
         </ol>
       </fieldset>
diff --git a/templates/identity/email-password/register-response.html.ejs b/templates/identity/email-password/register-response.html.ejs
index 3bbe29e72..46dee30c7 100644
--- a/templates/identity/email-password/register-response.html.ejs
+++ b/templates/identity/email-password/register-response.html.ejs
@@ -19,9 +19,9 @@
     </p>
 
     <% if (createPod) { %>
-      <h2>Your new pod</h2>
+      <h2>Your new Pod</h2>
       <p>
-        Your new pod is located at <a href="<%= podBaseUrl %>" class="link"><%= podBaseUrl %></a>.
+        Your new Pod is located at <a href="<%= podBaseUrl %>" class="link"><%= podBaseUrl %></a>.
         <br>
         You can store your documents and data there.
       </p>
@@ -37,18 +37,18 @@
     <% } %>
 
     <% if (register) { %>
-      <h2>Your new login</h2>
+      <h2>Your new account</h2>
       <p>
-        You can <a href="./login">log in</a>
-        with your WebID <a href="<%= webId %>" class="link"><%= webId %></a>
-        on this server via your email address <em><%= email %></em>.
+        Via your email address <em><%= email %></em>,
+        this server lets you <a href="./login">log in</a> to Solid apps
+        with your WebID <a href="<%= webId %>" class="link"><%= webId %></a>
       </p>
       <% if (!createWebId) { %>
         <p>
           You will need to add the triple
           <code><%= `<${webId}> <http://www.w3.org/ns/solid/terms#oidcIssuer> <${oidcIssuer}>.`%></code>
           to your existing WebID document <em><%= webId %></em>
-          to indicate that you trust this server as a login provider for your WebID.
+          to indicate that you trust this server as a login provider.
         </p>
       <% } %>
     <% } %>
diff --git a/templates/identity/email-password/register.html.ejs b/templates/identity/email-password/register.html.ejs
index 448ac5bf6..9ffb990ce 100644
--- a/templates/identity/email-password/register.html.ejs
+++ b/templates/identity/email-password/register.html.ejs
@@ -12,58 +12,195 @@
     <h1>Community Solid Server</h1>
   </header>
   <main>
-    <h1>Sign up for an account</h1>
-    <form action="/idp/register" method="post">
+    <h1>Sign up</h1>
+    <form action="/idp/register" method="post" id="mainForm">
+      <% const isBlankForm = !('email' in prefilled); %>
 
-      <%if (errorMessage) { %>
+      <% if (errorMessage) { %>
         <p class="error">Error: <%= errorMessage %></p>
       <% } %>
 
       <fieldset>
+        <legend>Your WebID</legend>
+        <p>
+          A <em>WebID</em> is a unique identifier for you
+          in the form of a URL.
+          <br>
+          You WebID lets you log in to Solid apps
+          and access non-public data in Pods.
+        </p>
         <ol>
-          <li>
-            <label for="email">Email</label>
-            <input id="email" type="text" name="email" autofocus <% if (prefilled.email) { %> value="<%= prefilled.email %>" <% } %> />
+          <li class="radio">
+            <label>
+              <input type="radio" id="createWebIdOn" name="createWebId" value="on"<%
+                if (isBlankForm || prefilled.createWebId) { %> checked<% } %>>
+              Create a new WebID for my Pod.
+            </label>
+            <p id="createWebIdForm">
+              Please also create a Pod below, since your WebID will be stored there.
+            </p>
           </li>
-          <li>
-            <label for="password">Password</label>
-            <input id="password" type="password" name="password" />
-          </li>
-          <li>
-            <label for="confirmPassword">Confirm password</label>
-            <input id="confirmPassword" type="password" name="confirmPassword" />
+          <li class="radio">
+            <label>
+              <input type="radio" id="createWebIdOff" name="createWebId" value=""<%
+                if (!isBlankForm && !prefilled.createWebId) { %> checked<% } %>>
+              Use my existing WebID to access my Pod.
+            </label>
+            <ol id="existingWebIdForm">
+              <li>
+                <label for="webId">Existing WebID:</label>
+                <input id="webId" type="text" name="webId" value="<%= prefilled.webId || '' %>">
+              </li>
+              <li class="checkbox">
+                <label>
+                  <input type="checkbox" id="register" name="register"<%
+                    if (isBlankForm || prefilled.register) { %> checked<% } %>>
+                  Use my new account to log in with this WebID.
+                </label>
+              </li>
+            </ol>
           </li>
         </ol>
       </fieldset>
 
       <fieldset>
+        <legend>Your Pod</legend>
+        <p>
+          A Pod is a place to store your data.
+          <br>
+          If you create a new WebID, you must also create a Pod to store that WebID.
+        </p>
         <ol>
           <li class="checkbox">
-            <label><input type="checkbox" name="createWebId" checked>Create a new WebID <em>(requires the other two options)</em></label>
-          </li>
-          <li class="checkbox">
-            <label><input type="checkbox" name="register" checked>Register your WebID with the IDP</label>
-            <ol>
-              <li>
-                <label for="webId">Alternatively, existing WebID</label>
-                <input id="webId" type="text" name="webId" <% if (prefilled.webId) { %> value="<%= prefilled.webId %>" <% } %> />
-              </li>
-            </ol>
-          </li>
-          <li class="checkbox">
-            <label><input type="checkbox" name="createPod" checked>Create a new pod</label>
-            <ol>
+            <label>
+              <input type="checkbox" id="createPod" name="createPod"<%
+                if (isBlankForm || prefilled.createPod) { %> checked<% } %>>
+              Create a new Pod with my WebID as owner.
+            </label>
+            <ol id="createPodForm">
               <li>
-                <label for="podName">Pod name</label>
-                <input id="podName" type="text" name="podName" <% if (prefilled.podName) { %> value="<%= prefilled.podName %>" <% } %> />
+                <label for="podName">Pod name:</label>
+                <input id="podName" type="text" name="podName" <%
+                  if (prefilled.podName) { %> value="<%= prefilled.podName %>" <% } %>>
               </li>
             </ol>
           </li>
         </ol>
       </fieldset>
 
+      <fieldset>
+        <legend>Your account</legend>
+        <div>
+          <p>
+            Choose the credentials you want to use to log in to this server in the future.
+          </p>
+          <ol>
+            <li>
+              <label for="email">Email:</label>
+              <input id="email" type="text" name="email" <%
+                if (prefilled.email) { %> value="<%= prefilled.email %>" <% } %>>
+            </li>
+          </ol>
+          <ol id="passwordForm">
+            <li>
+              <label for="password">Password:</label>
+              <input id="password" type="password" name="password">
+            </li>
+            <li>
+              <label for="confirmPassword">Confirm password:</label>
+              <input id="confirmPassword" type="password" name="confirmPassword">
+            </li>
+          </ol>
+        </div>
+        <div id="noPasswordForm" class="hidden">
+          <p>
+            Since you will be using your existing WebID setup to access your pod,
+            <br>
+            you do <em>not</em> need to set a password.
+          </p>
+        </div>
+      </fieldset>
+
       <p class="actions"><button type="submit" name="submit">Sign up</button></p>
     </form>
+
+    <script>
+    // Assist the user with filling out the form by hiding irrelevant fields
+    (() => {
+      // Wire up the UI elements
+      const elements = {};
+      [
+        'createWebIdOn', 'createWebIdOff', 'createWebIdForm', 'existingWebIdForm', 'webId',
+        'createPod', 'createPodForm', 'podName',
+        'register', 'passwordForm', 'noPasswordForm', 'mainForm',
+      ].forEach(id => {
+        elements[id] = document.getElementById(id);
+        elements[id].addEventListener('change', updateUI);
+      });
+      updateUI();
+      mainForm.classList.add('loaded');
+
+      // Updates the UI when something has changed
+      function updateUI({ srcElement } = {}) {
+        // When Pod creation is required, automatically tick the corresponding checkbox
+        if (elements.createWebIdOn.checked)
+          elements.createPod.checked = true;
+        elements.createPod.disabled = elements.createWebIdOn.checked;
+
+        // Hide irrelevant fields
+        setVisibility('createWebIdForm', elements.createWebIdOn.checked);
+        setVisibility('existingWebIdForm', elements.createWebIdOff.checked);
+        setVisibility('createPodForm', elements.createPod.checked);
+        setVisibility('passwordForm', elements.createWebIdOn.checked || elements.register.checked);
+        setVisibility('noPasswordForm', !isVisible('passwordForm'));
+
+        // If child elements have just been activated, focus on them
+        if (srcElement?.checked) {
+          switch(document.activeElement) {
+          case elements.createWebIdOff:
+            const { webId } = elements;
+            webId.value = webId.value.startsWith('http') ? webId.value : 'https://';
+            webId.focus();
+            break;
+          case elements.createPod:
+            elements.podName.focus();
+            break;
+          }
+        }
+      }
+
+      // Checks whether the given element is visible
+      function isVisible(element) {
+        return !(elements[element] ?? element).classList.contains('hidden');
+      }
+
+      // Sets the visibility of the given element
+      function setVisibility(element, visible) {
+        // Show or hide the element
+        element = elements[element] ?? element;
+        element.classList[visible ? 'remove' : 'add']('hidden');
+
+        // Disable children of hidden elements,
+        // such that the browser does not expect input for them
+        for (const child of getDescendants(element)) {
+          if ('disabled' in child)
+            child.disabled = !visible;
+        }
+      }
+
+      // Obtains all children, grandchildren, etc. of the given element
+      function getDescendants(element) {
+        return [...element.querySelectorAll("*")];
+      }
+
+      // Enable all elements on form submission (otherwise their value is not submitted)
+      elements.mainForm.addEventListener('submit', () => {
+        for (const child of getDescendants(elements.mainForm))
+          child.disabled = false;
+      });
+      elements.mainForm.addEventListener('formdata', updateUI);
+    })();
+    </script>
   </main>
   <footer>
     <p>
diff --git a/templates/styles/main.css b/templates/styles/main.css
index 0a0c6058c..d6603c7d8 100644
--- a/templates/styles/main.css
+++ b/templates/styles/main.css
@@ -72,10 +72,14 @@ header img {
 
 main h1 {
   margin: 1em 0 0;
+
+  font-size: 2em;
   font-weight: 700;
 }
 main h2 {
   margin: 1em 0 0;
+
+  font-size: 1.5em;
   font-weight: 600;
   color: var(--solid-gray);
 }
@@ -134,35 +138,49 @@ pre {
 fieldset {
   border: none;
   margin: 0;
-  padding: 0 0 0 1em;
+  padding: 0;
   max-width: 600px;
 }
+fieldset > legend {
+  margin: .5em 0 0;
+
+  font-size: 1.5em;
+  font-weight: 600;
+  color: var(--solid-gray);
+}
+fieldset > legend + p {
+  margin: 0 0 .5em .25em;
+}
 fieldset ol {
   list-style: none;
-  margin; 0;
-  padding: 0;
+  margin: 0;
+  padding: 0 0 0 2em;
 }
 fieldset ol ol {
-  margin: 0 0 1em 2em;
+  margin: 0 0 1em .5em;
 }
-fieldset ol li:not(.checkbox) {
+fieldset ol li:not(.checkbox, .radio) {
   display: grid;
   grid-template-columns: 10em auto;
   grid-gap: 1em;
   align-items: center;
 }
-fieldset ol ol li:not(.checkbox) {
-  grid-template-columns: 8em auto;
+fieldset ol ol li:not(.checkbox, .radio) {
+  grid-template-columns: 7.5em auto;
 }
 fieldset li label {
   font-weight: 600;
 }
-fieldset li:not(.checkbox) > label:after {
-  content: ": ";
+fieldset li li label {
+  font-weight: 500;
 }
-fieldset li.checkbox > label > input {
+fieldset li.checkbox > label > input,
+fieldset li.radio > label > input {
   margin: 0 .5em 0 0;
 }
+fieldset li p {
+  margin-top: .25em;
+}
 
 input {
   border: 1px solid var(--solid-purple);
@@ -183,7 +201,7 @@ button:hover {
 }
 
 form p.actions {
-  margin: 0 0 1em 12em;
+  margin: .5em 0 1em 11em;
 }
 
 form p.error {
@@ -193,7 +211,7 @@ form p.error {
 
 form ul.actions {
   padding: 0;
-  margin: 0 0 1em 12em;
+  margin: 0 0 1em 11em;
 }
 form ul.actions > li {
   list-style-type: none;
@@ -201,6 +219,15 @@ form ul.actions > li {
   margin-right: 1em;
 }
 
+form.loaded * {
+  max-height: 500px;
+  transition: max-height .2s;
+}
+form .hidden {
+  max-height: 0;
+  overflow: hidden;
+}
+
 ul.container > li {
   margin: 0.25em 0;
   list-style-type: none;


Test patch:
diff --git a/test/integration/Identity.test.ts b/test/integration/Identity.test.ts
index 203c40b5b..1e8903211 100644
--- a/test/integration/Identity.test.ts
+++ b/test/integration/Identity.test.ts
@@ -117,8 +117,8 @@ describe('A Solid server with IDP', (): void => {
       const res = await postForm(`${baseUrl}idp/register`, formBody);
       expect(res.status).toBe(200);
       const text = await res.text();
-      expect(text).toMatch(new RegExp(`your WebID.*${webId}`, 'u'));
-      expect(text).toMatch(new RegExp(`your email address.*${email}`, 'u'));
+      expect(text).toMatch(new RegExp(`your.WebID.*${webId}`, 'u'));
+      expect(text).toMatch(new RegExp(`your.email.address.*${email}`, 'u'));
       expect(text).toMatch(new RegExp(`<code>&lt;${webId}&gt; &lt;http://www.w3.org/ns/solid/terms#oidcIssuer&gt; &lt;${baseUrl}&gt;\\.</code>`, 'mu'));
     });
   });
@@ -280,7 +280,7 @@ describe('A Solid server with IDP', (): void => {
       const res = await postForm(`${baseUrl}idp/register`, formBody);
       expect(res.status).toBe(200);
       const text = await res.text();
-      expect(text).toMatch(new RegExp(`Your new pod.*${baseUrl}${podName}/`, 'u'));
+      expect(text).toMatch(new RegExp(`Your new Pod.*${baseUrl}${podName}/`, 'u'));
     });
   });
 
@@ -305,7 +305,7 @@ describe('A Solid server with IDP', (): void => {
       newWebId = matchWebId![1];
       expect(text).toMatch(new RegExp(`new WebID is.*${newWebId}`, 'u'));
       expect(text).toMatch(new RegExp(`your email address.*${newMail}`, 'u'));
-      expect(text).toMatch(new RegExp(`Your new pod.*${baseUrl}${podName}/`, 'u'));
+      expect(text).toMatch(new RegExp(`Your new Pod.*${baseUrl}${podName}/`, 'u'));
     });
 
     it('initializes the session and logs in.', async(): Promise<void> => {
diff --git a/test/unit/identity/interaction/email-password/EmailPasswordUtil.test.ts b/test/unit/identity/interaction/email-password/EmailPasswordUtil.test.ts
index 096140f70..3f74896ba 100644
--- a/test/unit/identity/interaction/email-password/EmailPasswordUtil.test.ts
+++ b/test/unit/identity/interaction/email-password/EmailPasswordUtil.test.ts
@@ -53,12 +53,11 @@ describe('EmailPasswordUtil', (): void => {
 
   describe('#assertPassword', (): void => {
     it('validates the password against the confirmPassword.', async(): Promise<void> => {
-      expect((): void => assertPassword(undefined, undefined)).toThrow('Password required');
-      expect((): void => assertPassword([], undefined)).toThrow('Password required');
-      expect((): void => assertPassword('password', undefined)).toThrow('Password confirmation required');
-      expect((): void => assertPassword('password', [])).toThrow('Password confirmation required');
-      expect((): void => assertPassword('password', 'confirmPassword'))
-        .toThrow('Password and confirmation do not match');
+      expect((): void => assertPassword(undefined, undefined)).toThrow('Please enter a password.');
+      expect((): void => assertPassword([], undefined)).toThrow('Please enter a password.');
+      expect((): void => assertPassword('password', undefined)).toThrow('Please confirm your password.');
+      expect((): void => assertPassword('password', [])).toThrow('Please confirm your password.');
+      expect((): void => assertPassword('password', 'other')).toThrow('Your password and confirmation did not match');
       expect(assertPassword('password', 'password')).toBeUndefined();
     });
   });
diff --git a/test/unit/identity/interaction/email-password/handler/RegistrationHandler.test.ts b/test/unit/identity/interaction/email-password/handler/RegistrationHandler.test.ts
index 278ca1a1f..444b1122d 100644
--- a/test/unit/identity/interaction/email-password/handler/RegistrationHandler.test.ts
+++ b/test/unit/identity/interaction/email-password/handler/RegistrationHandler.test.ts
@@ -78,81 +78,73 @@ describe('A RegistrationHandler', (): void => {
 
   describe('validating data', (): void => {
     it('rejects array inputs.', async(): Promise<void> => {
-      request = createPostFormRequest({ data: [ 'a', 'b' ]});
-      await expect(handler.handle({ request, response })).rejects.toThrow('Multiple values found for key data');
+      request = createPostFormRequest({ mydata: [ 'a', 'b' ]});
+      await expect(handler.handle({ request, response }))
+        .rejects.toThrow('Unexpected multiple values for mydata.');
     });
 
     it('errors on invalid emails.', async(): Promise<void> => {
       request = createPostFormRequest({ email: undefined });
-      await expect(handler.handle({ request, response })).rejects.toThrow('A valid e-mail address is required');
+      await expect(handler.handle({ request, response }))
+        .rejects.toThrow('Please enter a valid e-mail address.');
 
       request = createPostFormRequest({ email: '' });
-      await expect(handler.handle({ request, response })).rejects.toThrow('A valid e-mail address is required');
+      await expect(handler.handle({ request, response }))
+        .rejects.toThrow('Please enter a valid e-mail address.');
 
       request = createPostFormRequest({ email: 'invalidEmail' });
-      await expect(handler.handle({ request, response })).rejects.toThrow('A valid e-mail address is required');
-    });
-
-    it('errors when an unnecessary WebID is provided.', async(): Promise<void> => {
-      request = createPostFormRequest({ email, webId, createWebId });
       await expect(handler.handle({ request, response }))
-        .rejects.toThrow('A WebID should only be provided when no new one is being created');
+        .rejects.toThrow('Please enter a valid e-mail address.');
     });
 
     it('errors when a required WebID is not valid.', async(): Promise<void> => {
-      request = createPostFormRequest({ email, webId: undefined });
-      await expect(handler.handle({ request, response }))
-        .rejects.toThrow('A WebID is required if no new one is being created');
-
-      request = createPostFormRequest({ email, webId: '' });
+      request = createPostFormRequest({ email, register, webId: undefined });
       await expect(handler.handle({ request, response }))
-        .rejects.toThrow('A WebID is required if no new one is being created');
-    });
+        .rejects.toThrow('Please enter a valid WebID.');
 
-    it('errors when an unnecessary password is provided.', async(): Promise<void> => {
-      request = createPostFormRequest({ email, webId, password });
+      request = createPostFormRequest({ email, register, webId: '' });
       await expect(handler.handle({ request, response }))
-        .rejects.toThrow('A password should only be provided when registering');
+        .rejects.toThrow('Please enter a valid WebID.');
     });
 
     it('errors on invalid passwords when registering.', async(): Promise<void> => {
       request = createPostFormRequest({ email, webId, password, confirmPassword: 'bad', register });
-      await expect(handler.handle({ request, response })).rejects.toThrow('Password and confirmation do not match');
-    });
-
-    it('errors when an unnecessary pod name is provided.', async(): Promise<void> => {
-      request = createPostFormRequest({ email, webId, podName });
       await expect(handler.handle({ request, response }))
-        .rejects.toThrow('A pod name should only be provided when creating a pod and/or WebID');
+        .rejects.toThrow('Your password and confirmation did not match.');
     });
 
     it('errors on invalid pod names when required.', async(): Promise<void> => {
-      request = createPostFormRequest({ email, podName: undefined, createWebId });
+      request = createPostFormRequest({ email, webId, createPod, podName: undefined });
+      await expect(handler.handle({ request, response }))
+        .rejects.toThrow('Please specify a Pod name.');
+
+      request = createPostFormRequest({ email, webId, createPod, podName: ' ' });
       await expect(handler.handle({ request, response }))
-        .rejects.toThrow('A pod name is required when creating a pod and/or WebID');
+        .rejects.toThrow('Please specify a Pod name.');
 
-      request = createPostFormRequest({ email, webId, podName: '', createPod });
+      request = createPostFormRequest({ email, webId, createWebId });
       await expect(handler.handle({ request, response }))
-        .rejects.toThrow('A pod name is required when creating a pod and/or WebID');
+        .rejects.toThrow('Please specify a Pod name.');
     });
 
     it('errors when trying to create a WebID without registering or creating a pod.', async(): Promise<void> => {
       request = createPostFormRequest({ email, podName, createWebId });
       await expect(handler.handle({ request, response }))
-        .rejects.toThrow('Creating a WebID is only possible when also registering and creating a pod');
+        .rejects.toThrow('Please enter a password.');
 
-      request = createPostFormRequest({ email, podName, password, confirmPassword, createWebId, register });
+      request = createPostFormRequest({ email, podName, createWebId, createPod });
       await expect(handler.handle({ request, response }))
-        .rejects.toThrow('Creating a WebID is only possible when also registering and creating a pod');
+        .rejects.toThrow('Please enter a password.');
 
-      request = createPostFormRequest({ email, podName, createWebId, createPod });
+      request = createPostFormRequest({ email, podName, createWebId, createPod, register });
       await expect(handler.handle({ request, response }))
-        .rejects.toThrow('Creating a WebID is only possible when also registering and creating a pod');
+        .rejects.toThrow('Please enter a password.');
     });
 
     it('errors when no option is chosen.', async(): Promise<void> => {
       request = createPostFormRequest({ email, webId });
-      await expect(handler.handle({ request, response })).rejects.toThrow('At least one option needs to be chosen');
+      await expect(handler.handle({ request, response }))
+        .rejects.toThrow('Please register for a WebID or create a Pod.');
     });
   });
 
diff --git a/test/unit/identity/interaction/email-password/handler/ResetPasswordHandler.test.ts b/test/unit/identity/interaction/email-password/handler/ResetPasswordHandler.test.ts
index d9ff3cab0..19cd6ca6b 100644
--- a/test/unit/identity/interaction/email-password/handler/ResetPasswordHandler.test.ts
+++ b/test/unit/identity/interaction/email-password/handler/ResetPasswordHandler.test.ts
@@ -43,7 +43,7 @@ describe('A ResetPasswordHandler', (): void => {
   });
 
   it('errors for invalid passwords.', async(): Promise<void> => {
-    const errorMessage = 'Password and confirmation do not match';
+    const errorMessage = 'Your password and confirmation did not match.';
     request = createPostFormRequest({ password: 'password!', confirmPassword: 'otherPassword!' }, url);
     await expect(handler.handle({ request, response })).rejects.toThrow(errorMessage);
   });