Skip to content

Commit 4c93644

Browse files
author
Akos Kitta
committed
feat: better error handling for cloud sketches
Signed-off-by: Akos Kitta <[email protected]>
1 parent 4af488b commit 4c93644

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

arduino-ide-extension/src/browser/create/typings.ts

+7
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ export function isNotFound(err: unknown): err is NotFoundError {
8282
return isErrorWithStatusOf(err, 404);
8383
}
8484

85+
export type UnprocessableContentError = CreateError & { status: 422 };
86+
export function isUnprocessableContent(
87+
err: unknown
88+
): err is UnprocessableContentError {
89+
return isErrorWithStatusOf(err, 422);
90+
}
91+
8592
function isErrorWithStatusOf(
8693
err: unknown,
8794
status: number

arduino-ide-extension/src/test/browser/create-api.test.ts

+51-2
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,23 @@ import {
55
} from '@theia/core/shared/inversify';
66
import { assert, expect } from 'chai';
77
import fetch from 'cross-fetch';
8+
import { rejects } from 'node:assert';
89
import { posix } from 'node:path';
10+
import queryString from 'query-string';
911
import { v4 } from 'uuid';
1012
import { ArduinoPreferences } from '../../browser/arduino-preferences';
1113
import { AuthenticationClientService } from '../../browser/auth/authentication-client-service';
1214
import { CreateApi } from '../../browser/create/create-api';
1315
import { splitSketchPath } from '../../browser/create/create-paths';
14-
import { Create, CreateError } from '../../browser/create/typings';
16+
import {
17+
Create,
18+
CreateError,
19+
isNotFound,
20+
isUnprocessableContent,
21+
} from '../../browser/create/typings';
1522
import { SketchCache } from '../../browser/widgets/cloud-sketchbook/cloud-sketch-cache';
1623
import { SketchesService } from '../../common/protocol';
1724
import { AuthenticationSession } from '../../node/auth/types';
18-
import queryString from 'query-string';
1925

2026
/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */
2127
/* eslint-disable @typescript-eslint/no-non-null-assertion */
@@ -229,6 +235,49 @@ describe('create-api', () => {
229235
expect(findByName(otherName, sketches)).to.be.not.undefined;
230236
});
231237

238+
it('should fail with HTTP 422 when reading a file but is a directory', async () => {
239+
const name = v4();
240+
const content = 'void setup(){} void loop(){}';
241+
const posixPath = toPosix(name);
242+
243+
await createApi.createSketch(posixPath, content);
244+
const resources = await createApi.readDirectory(posixPath);
245+
expect(resources.length > 0).to.be.true;
246+
247+
await rejects(createApi.readFile(posixPath), (thrown) =>
248+
isUnprocessableContent(thrown)
249+
);
250+
});
251+
252+
it('should fail with HTTP 422 when listing a directory but is a file', async () => {
253+
const name = v4();
254+
const content = 'void setup(){} void loop(){}';
255+
const posixPath = toPosix(name);
256+
257+
await createApi.createSketch(posixPath, content);
258+
const sketchContent = await createApi.readFile(
259+
posixPath + posixPath + '.ino'
260+
);
261+
expect(sketchContent).to.be.equal(content);
262+
263+
await rejects(createApi.deleteDirectory(posixPath), (thrown) =>
264+
isUnprocessableContent(thrown)
265+
);
266+
});
267+
268+
it("should fail with HTTP 404 when deleting a non-existing directory via the '/files/d' endpoint", async () => {
269+
const name = v4();
270+
const posixPath = toPosix(name);
271+
272+
const sketches = await createApi.sketches();
273+
const sketch = findByName(name, sketches);
274+
expect(sketch).to.be.undefined;
275+
276+
await rejects(createApi.deleteDirectory(posixPath), (thrown) =>
277+
isNotFound(thrown)
278+
);
279+
});
280+
232281
['.', '-', '_'].map((char) => {
233282
it(`should create a new sketch with '${char}' in the sketch folder name although it's disallowed from the Create Editor`, async () => {
234283
const name = `sketch${char}`;

0 commit comments

Comments
 (0)