From 010e4ecf31f2300f6c009aca449654f3a12f3065 Mon Sep 17 00:00:00 2001 From: Obinna Emmanuel Obi-Akwari Date: Fri, 25 Jul 2025 00:40:33 +0100 Subject: [PATCH 1/4] add error-handling exercise --- config.json | 8 ++++ .../error-handling/.docs/instructions.md | 8 ++++ .../error-handling/.docs/introduction.md | 19 ++++++++ exercises/practice/error-handling/.gitignore | 5 +++ .../practice/error-handling/.meta/config.json | 15 +++++++ .../practice/error-handling/.meta/proof.ci.js | 0 exercises/practice/error-handling/.npmrc | 1 + exercises/practice/error-handling/LICENSE | 21 +++++++++ .../practice/error-handling/babel.config.js | 4 ++ .../practice/error-handling/error-handling.js | 0 .../error-handling/error-handling.spec.js | 37 +++++++++++++++ .../practice/error-handling/eslint.config.mjs | 45 +++++++++++++++++++ .../practice/error-handling/jest.config.js | 22 +++++++++ .../practice/error-handling/package.json | 38 ++++++++++++++++ 14 files changed, 223 insertions(+) create mode 100644 exercises/practice/error-handling/.docs/instructions.md create mode 100644 exercises/practice/error-handling/.docs/introduction.md create mode 100644 exercises/practice/error-handling/.gitignore create mode 100644 exercises/practice/error-handling/.meta/config.json create mode 100644 exercises/practice/error-handling/.meta/proof.ci.js create mode 100644 exercises/practice/error-handling/.npmrc create mode 100644 exercises/practice/error-handling/LICENSE create mode 100644 exercises/practice/error-handling/babel.config.js create mode 100644 exercises/practice/error-handling/error-handling.js create mode 100644 exercises/practice/error-handling/error-handling.spec.js create mode 100644 exercises/practice/error-handling/eslint.config.mjs create mode 100644 exercises/practice/error-handling/jest.config.js create mode 100644 exercises/practice/error-handling/package.json diff --git a/config.json b/config.json index ddc35cb96d..8d8a0a818f 100644 --- a/config.json +++ b/config.json @@ -2720,6 +2720,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "error-handling", + "name": "Error Handling", + "uuid": "de1c75f2-2461-4347-b5ca-b3cfaafe4d79", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ] }, diff --git a/exercises/practice/error-handling/.docs/instructions.md b/exercises/practice/error-handling/.docs/instructions.md new file mode 100644 index 0000000000..25dd4d2928 --- /dev/null +++ b/exercises/practice/error-handling/.docs/instructions.md @@ -0,0 +1,8 @@ +# Instructions + +Implement various kinds of error handling and resource management. + +An important point of programming is how to handle errors and close resources even if errors occur. + +This exercise requires you to handle various errors. +Because error handling is rather programming language specific you'll have to refer to the tests for your track to see what's exactly required. diff --git a/exercises/practice/error-handling/.docs/introduction.md b/exercises/practice/error-handling/.docs/introduction.md new file mode 100644 index 0000000000..4ccfc70c47 --- /dev/null +++ b/exercises/practice/error-handling/.docs/introduction.md @@ -0,0 +1,19 @@ +# Error Handling + +In this exercise, you will implement a function called `processString` that processes a given input string with proper error handling. + +You will learn how to: + +- Check input types and handle invalid inputs by throwing errors. +- Throw custom errors for specific cases (e.g., empty strings). +- Use a `try...finally` block to ensure certain code runs regardless of success or failure (such as cleanup or logging). +- Return the uppercase version of the string if it is valid. + +Your function should: + +- Throw a `TypeError` if the input is not a string. +- Throw an `Error` with the message `EmptyStringError` if the input string is empty. +- Return the uppercase form of the input string if valid. +- Use a `finally` block to log a cleanup message every time the function runs. + +This exercise is a great way to practice writing robust functions that can gracefully handle unexpected inputs while always executing necessary cleanup logic. diff --git a/exercises/practice/error-handling/.gitignore b/exercises/practice/error-handling/.gitignore new file mode 100644 index 0000000000..0c88ff6ec3 --- /dev/null +++ b/exercises/practice/error-handling/.gitignore @@ -0,0 +1,5 @@ +/node_modules +/bin/configlet +/bin/configlet.exe +/package-lock.json +/yarn.lock diff --git a/exercises/practice/error-handling/.meta/config.json b/exercises/practice/error-handling/.meta/config.json new file mode 100644 index 0000000000..9d8f7dd2f4 --- /dev/null +++ b/exercises/practice/error-handling/.meta/config.json @@ -0,0 +1,15 @@ +{ + "authors": ["Obinna Obi-Akwari"], + "files": { + "solution": [ + "error-handling.js" + ], + "test": [ + "error-handling.spec.js" + ], + "example": [ + ".meta/proof.ci.js" + ] + }, + "blurb": "Implement various kinds of error handling and resource management." +} diff --git a/exercises/practice/error-handling/.meta/proof.ci.js b/exercises/practice/error-handling/.meta/proof.ci.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/error-handling/.npmrc b/exercises/practice/error-handling/.npmrc new file mode 100644 index 0000000000..d26df800bb --- /dev/null +++ b/exercises/practice/error-handling/.npmrc @@ -0,0 +1 @@ +audit=false diff --git a/exercises/practice/error-handling/LICENSE b/exercises/practice/error-handling/LICENSE new file mode 100644 index 0000000000..90e73be03b --- /dev/null +++ b/exercises/practice/error-handling/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Exercism + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/exercises/practice/error-handling/babel.config.js b/exercises/practice/error-handling/babel.config.js new file mode 100644 index 0000000000..a638497df1 --- /dev/null +++ b/exercises/practice/error-handling/babel.config.js @@ -0,0 +1,4 @@ +module.exports = { + presets: [['@exercism/babel-preset-javascript', { corejs: '3.40' }]], + plugins: [], +}; diff --git a/exercises/practice/error-handling/error-handling.js b/exercises/practice/error-handling/error-handling.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/error-handling/error-handling.spec.js b/exercises/practice/error-handling/error-handling.spec.js new file mode 100644 index 0000000000..0d969c8383 --- /dev/null +++ b/exercises/practice/error-handling/error-handling.spec.js @@ -0,0 +1,37 @@ + +import { describe, expect, it, jest } from '@jest/globals'; +import { processString } from './error-handling'; + + +describe('Error Handling', () => { + it('returns uppercase if valid string', () => { + expect(processString('hello')).toBe('HELLO'); + }); + + it('throws TypeError if input is not a string', () => { + expect(() => processString(42)).toThrow(TypeError); + expect(() => processString(42)).toThrow('input must be a string'); + }); + + it('throws Error with EmptyStringError if string is empty', () => { + expect(() => processString('')).toThrow(Error); + expect(() => processString('')).toThrow('EmptyStringError'); + }); + + it('always logs cleanup message', () => { + console.log = jest.fn(); + + try { + processString(''); + } catch { + /* + intentionally left empty, + I expext this call to throw, + but only care about verifying that the finally block is executed + and clean up message logged. + */ + } + + expect(console.log).toHaveBeenCalledWith('Resource cleaned up'); + }); +}); diff --git a/exercises/practice/error-handling/eslint.config.mjs b/exercises/practice/error-handling/eslint.config.mjs new file mode 100644 index 0000000000..ca517111ed --- /dev/null +++ b/exercises/practice/error-handling/eslint.config.mjs @@ -0,0 +1,45 @@ +// @ts-check + +import config from '@exercism/eslint-config-javascript'; +import maintainersConfig from '@exercism/eslint-config-javascript/maintainers.mjs'; + +import globals from 'globals'; + +export default [ + ...config, + ...maintainersConfig, + { + files: maintainersConfig[1].files, + rules: { + 'jest/expect-expect': ['warn', { assertFunctionNames: ['expect*'] }], + }, + }, + { + files: ['scripts/**/*.mjs'], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, + // <> + { + ignores: [ + // # Protected or generated + '/.appends/**/*', + '/.github/**/*', + '/.vscode/**/*', + + // # Binaries + '/bin/*', + + // # Configuration + '/config', + '/babel.config.js', + + // # Typings + '/exercises/**/global.d.ts', + '/exercises/**/env.d.ts', + ], + }, +]; diff --git a/exercises/practice/error-handling/jest.config.js b/exercises/practice/error-handling/jest.config.js new file mode 100644 index 0000000000..ec8e908127 --- /dev/null +++ b/exercises/practice/error-handling/jest.config.js @@ -0,0 +1,22 @@ +module.exports = { + verbose: true, + projects: [''], + testMatch: [ + '**/__tests__/**/*.[jt]s?(x)', + '**/test/**/*.[jt]s?(x)', + '**/?(*.)+(spec|test).[jt]s?(x)', + ], + testPathIgnorePatterns: [ + '/(?:production_)?node_modules/', + '.d.ts$', + '/test/fixtures', + '/test/helpers', + '__mocks__', + ], + transform: { + '^.+\\.[jt]sx?$': 'babel-jest', + }, + moduleNameMapper: { + '^(\\.\\/.+)\\.js$': '$1', + }, +}; diff --git a/exercises/practice/error-handling/package.json b/exercises/practice/error-handling/package.json new file mode 100644 index 0000000000..eacd446caf --- /dev/null +++ b/exercises/practice/error-handling/package.json @@ -0,0 +1,38 @@ +{ + "name": "@exercism/javascript-practice-error-handling", + "description": "Exercism practice exercise on error-handling", + "author": "Katrina Owen", + "contributors": [ + "Derk-Jan Karrenbeld (https://derk-jan.com)", + "Tejas Bubane (https://tejasbubane.github.io/)" + ], + "private": true, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/exercism/javascript", + "directory": "exercises/practice/error-handling" + }, + "devDependencies": { + "@exercism/babel-preset-javascript": "^0.5.1", + "@exercism/eslint-config-javascript": "^0.8.1", + "@jest/globals": "^29.7.0", + "@types/node": "^22.15.29", + "@types/shelljs": "^0.8.17", + "babel-jest": "^29.7.0", + "core-js": "~3.42.0", + "diff": "^8.0.2", + "eslint": "^9.28.0", + "expect": "^29.7.0", + "globals": "^16.2.0", + "jest": "^29.7.0" + }, + "dependencies": {}, + "scripts": { + "lint": "corepack pnpm eslint .", + "test": "corepack pnpm jest", + "watch": "corepack pnpm jest --watch", + "format": "corepack pnpm prettier -w ." + }, + "packageManager": "pnpm@9.15.2" +} From 69a0b956ed3e41db789320f1da936160b6ec058c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 25 Jul 2025 00:13:56 +0000 Subject: [PATCH 2/4] [CI] Format code --- exercises/practice/error-handling/error-handling.spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/exercises/practice/error-handling/error-handling.spec.js b/exercises/practice/error-handling/error-handling.spec.js index 0d969c8383..9ad32b2415 100644 --- a/exercises/practice/error-handling/error-handling.spec.js +++ b/exercises/practice/error-handling/error-handling.spec.js @@ -1,8 +1,6 @@ - import { describe, expect, it, jest } from '@jest/globals'; import { processString } from './error-handling'; - describe('Error Handling', () => { it('returns uppercase if valid string', () => { expect(processString('hello')).toBe('HELLO'); From 0c7088352ede29d89a9dbc45b378be2aae9d9c11 Mon Sep 17 00:00:00 2001 From: Obinna Emmanuel Obi-Akwari Date: Tue, 29 Jul 2025 01:27:57 +0100 Subject: [PATCH 3/4] add github username and update proof.ci.js and error-handling.js --- .../practice/error-handling/.meta/config.json | 4 +++- .../practice/error-handling/.meta/proof.ci.js | 14 ++++++++++++++ .../practice/error-handling/error-handling.js | 7 +++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/exercises/practice/error-handling/.meta/config.json b/exercises/practice/error-handling/.meta/config.json index 9d8f7dd2f4..d657caee5e 100644 --- a/exercises/practice/error-handling/.meta/config.json +++ b/exercises/practice/error-handling/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": ["Obinna Obi-Akwari"], + "authors": [ + "A-O-Emmanuel" + ], "files": { "solution": [ "error-handling.js" diff --git a/exercises/practice/error-handling/.meta/proof.ci.js b/exercises/practice/error-handling/.meta/proof.ci.js index e69de29bb2..7401f24de5 100644 --- a/exercises/practice/error-handling/.meta/proof.ci.js +++ b/exercises/practice/error-handling/.meta/proof.ci.js @@ -0,0 +1,14 @@ +export const processString = (input) => { + try { + if (typeof input !== 'string') { + throw new TypeError('input must be a string'); + } + if (input === '') { + throw new Error('EmptyStringError'); + } + return input.toUpperCase(); + } finally { + console.log('Resource cleaned up'); + } +} + diff --git a/exercises/practice/error-handling/error-handling.js b/exercises/practice/error-handling/error-handling.js index e69de29bb2..f370b8f434 100644 --- a/exercises/practice/error-handling/error-handling.js +++ b/exercises/practice/error-handling/error-handling.js @@ -0,0 +1,7 @@ +export const processString = (input) => { + //TODO: implement this + //should throw Error if input is not a string + //should throw Error if input is an empty string + //should return the uppercase version of the string if valid + //should use finally to log cleanup message +} From 272f673c7d47b9dbb1ab96494d44b1491f403214 Mon Sep 17 00:00:00 2001 From: Obinna Emmanuel Obi-Akwari Date: Sun, 3 Aug 2025 00:06:27 +0100 Subject: [PATCH 4/4] Edit introduction and update proof.ci.js, error-handling.js, and error-handling.spec.js --- .../error-handling/.docs/introduction.md | 14 ++++----- .../practice/error-handling/.meta/proof.ci.js | 19 +++++------- .../practice/error-handling/error-handling.js | 11 ++++--- .../error-handling/error-handling.spec.js | 29 ++++--------------- 4 files changed, 22 insertions(+), 51 deletions(-) diff --git a/exercises/practice/error-handling/.docs/introduction.md b/exercises/practice/error-handling/.docs/introduction.md index 4ccfc70c47..cc0fae962a 100644 --- a/exercises/practice/error-handling/.docs/introduction.md +++ b/exercises/practice/error-handling/.docs/introduction.md @@ -4,16 +4,12 @@ In this exercise, you will implement a function called `processString` that proc You will learn how to: -- Check input types and handle invalid inputs by throwing errors. -- Throw custom errors for specific cases (e.g., empty strings). -- Use a `try...finally` block to ensure certain code runs regardless of success or failure (such as cleanup or logging). +- Check input types and throw errors for invalid inputs. +- Throw errors for specific cases (e.g., empty strings). - Return the uppercase version of the string if it is valid. Your function should: -- Throw a `TypeError` if the input is not a string. -- Throw an `Error` with the message `EmptyStringError` if the input string is empty. -- Return the uppercase form of the input string if valid. -- Use a `finally` block to log a cleanup message every time the function runs. - -This exercise is a great way to practice writing robust functions that can gracefully handle unexpected inputs while always executing necessary cleanup logic. +- Throw a `TypeError` if input is not a string. +- Throw a general `Error` if input is an empty string. +- Return the uppercase form of the string 'hello'. diff --git a/exercises/practice/error-handling/.meta/proof.ci.js b/exercises/practice/error-handling/.meta/proof.ci.js index 7401f24de5..de9102d770 100644 --- a/exercises/practice/error-handling/.meta/proof.ci.js +++ b/exercises/practice/error-handling/.meta/proof.ci.js @@ -1,14 +1,9 @@ export const processString = (input) => { - try { - if (typeof input !== 'string') { - throw new TypeError('input must be a string'); - } - if (input === '') { - throw new Error('EmptyStringError'); - } - return input.toUpperCase(); - } finally { - console.log('Resource cleaned up'); + if (typeof input !== 'string') { + throw new TypeError(); } -} - + if (input === '') { + throw new Error(); + } + return input.toUpperCase(); +}; diff --git a/exercises/practice/error-handling/error-handling.js b/exercises/practice/error-handling/error-handling.js index f370b8f434..fbbdf92c9f 100644 --- a/exercises/practice/error-handling/error-handling.js +++ b/exercises/practice/error-handling/error-handling.js @@ -1,7 +1,6 @@ export const processString = (input) => { - //TODO: implement this - //should throw Error if input is not a string - //should throw Error if input is an empty string - //should return the uppercase version of the string if valid - //should use finally to log cleanup message -} + //TODO: implement this + //should throw TypeError if input is not a string + //should throw a general Error if input is an empty string + //should return the uppercase version of the string 'hello' +}; diff --git a/exercises/practice/error-handling/error-handling.spec.js b/exercises/practice/error-handling/error-handling.spec.js index 9ad32b2415..eeb299140e 100644 --- a/exercises/practice/error-handling/error-handling.spec.js +++ b/exercises/practice/error-handling/error-handling.spec.js @@ -1,35 +1,16 @@ -import { describe, expect, it, jest } from '@jest/globals'; +import { describe, expect, test, xtest } from '@jest/globals'; import { processString } from './error-handling'; describe('Error Handling', () => { - it('returns uppercase if valid string', () => { - expect(processString('hello')).toBe('HELLO'); - }); - - it('throws TypeError if input is not a string', () => { + test('throws TypeError if input is not a string', () => { expect(() => processString(42)).toThrow(TypeError); - expect(() => processString(42)).toThrow('input must be a string'); }); - it('throws Error with EmptyStringError if string is empty', () => { + xtest('throws Error message if string is empty', () => { expect(() => processString('')).toThrow(Error); - expect(() => processString('')).toThrow('EmptyStringError'); }); - it('always logs cleanup message', () => { - console.log = jest.fn(); - - try { - processString(''); - } catch { - /* - intentionally left empty, - I expext this call to throw, - but only care about verifying that the finally block is executed - and clean up message logged. - */ - } - - expect(console.log).toHaveBeenCalledWith('Resource cleaned up'); + xtest('returns uppercase string if input is valid', () => { + expect(processString('hello')).toBe('HELLO'); }); });