From badda3ffc1c8ffc38c850b475e48439ff7af1dbb Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Wed, 20 Mar 2024 00:56:04 +0530 Subject: [PATCH] feat: flash validation errors summary to errorsBag --- package.json | 1 + src/session.ts | 21 ++++++++++++ tests/session.spec.ts | 78 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) diff --git a/package.json b/package.json index 1d3ae5d..15900fa 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@adonisjs/assembler": "^7.2.3", "@adonisjs/core": "^6.3.1", "@adonisjs/eslint-config": "^1.3.0", + "@adonisjs/i18n": "^2.0.1", "@adonisjs/prettier-config": "^1.3.0", "@adonisjs/redis": "^8.0.1", "@adonisjs/tsconfig": "^1.3.0", diff --git a/src/session.ts b/src/session.ts index 5b8c1c3..9287f16 100644 --- a/src/session.ts +++ b/src/session.ts @@ -7,6 +7,7 @@ * file that was distributed with this source code. */ +import type { I18n } from '@adonisjs/i18n' import lodash from '@poppinss/utils/lodash' import { cuid } from '@adonisjs/core/helpers' import type { HttpContext } from '@adonisjs/core/http' @@ -334,6 +335,26 @@ export class Session { this.flashExcept(['_csrf', '_method', 'password', 'password_confirmation']) + /** + * Adding the error summary to the "errorsBag" so that + * we display the validation error globally using + * the "@error" tag. + */ + let summary = 'The form could not be saved. Please check the errors below.' + if ('i18n' in this.#ctx) { + summary = (this.#ctx.i18n as I18n).t( + `errors.${error.code}`, + { + count: error.messages.length, + }, + summary + ) + } + + this.flashErrors({ + [String(error.code)]: summary, + }) + /** * Adding to inputErrorsBag for "@inputError" tag * to read validation errors diff --git a/tests/session.spec.ts b/tests/session.spec.ts index 745440b..95e88dc 100644 --- a/tests/session.spec.ts +++ b/tests/session.spec.ts @@ -17,6 +17,7 @@ import { SimpleErrorReporter } from '@vinejs/vine' import { CookieClient } from '@adonisjs/core/http' import { fieldContext } from '@vinejs/vine/factories' import { AppFactory } from '@adonisjs/core/factories/app' +import { I18nManagerFactory } from '@adonisjs/i18n/factories' import { ApplicationService, EventsList } from '@adonisjs/core/types' import { EncryptionFactory } from '@adonisjs/core/factories/encryption' import EdgeServiceProvider from '@adonisjs/core/providers/edge_provider' @@ -973,6 +974,80 @@ test.group('Session | Flash', (group) => { email: ['Invalid email'], username: ['Invalid username', 'Username is required'], }, + errorsBag: { + E_VALIDATION_ERROR: 'The form could not be saved. Please check the errors below.', + }, + inputErrorsBag: { + email: ['Invalid email'], + username: ['Invalid username', 'Username is required'], + }, + }, + }) + }) + + test('translate validation error summary', async ({ assert }) => { + const i18nManager = new I18nManagerFactory() + .merge({ + config: { + loaders: [ + () => { + return { + async load() { + return { + en: { + 'errors.E_VALIDATION_ERROR': '{count} errors prohibited form submission', + }, + } + }, + } + }, + ], + }, + }) + .create() + + await i18nManager.loadTranslations() + + let sessionId: string | undefined + + const server = httpServer.create(async (req, res) => { + const request = new RequestFactory().merge({ req, res, encryption }).create() + const response = new ResponseFactory().merge({ req, res, encryption }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + ctx.i18n = i18nManager.locale('en') + + const session = new Session(sessionConfig, cookieDriver, emitter, ctx) + await session.initiate(false) + + const errorReporter = new SimpleErrorReporter() + errorReporter.report('Invalid username', 'alpha', fieldContext.create('username', ''), {}) + errorReporter.report( + 'Username is required', + 'required', + fieldContext.create('username', ''), + {} + ) + errorReporter.report('Invalid email', 'email', fieldContext.create('email', ''), {}) + + session.flashValidationErrors(errorReporter.createError()) + sessionId = session.sessionId + + await session.commit() + response.finish() + }) + + const { headers } = await supertest(server).get('/') + const cookies = setCookieParser.parse(headers['set-cookie'], { map: true }) + + assert.deepEqual(cookieClient.decrypt(sessionId!, cookies[sessionId!].value), { + __flash__: { + errors: { + email: ['Invalid email'], + username: ['Invalid username', 'Username is required'], + }, + errorsBag: { + E_VALIDATION_ERROR: '3 errors prohibited form submission', + }, inputErrorsBag: { email: ['Invalid email'], username: ['Invalid username', 'Username is required'], @@ -1021,6 +1096,9 @@ test.group('Session | Flash', (group) => { errors: { name: ['Invalid name'], }, + errorsBag: { + E_VALIDATION_ERROR: 'The form could not be saved. Please check the errors below.', + }, inputErrorsBag: { name: ['Invalid name'], },