Skip to content

Commit

Permalink
feat: [#1315] Adds support for the Headers.getSetCookie()
Browse files Browse the repository at this point in the history
* feat: [#1315] Implement the getSetCookie method of Headers

* feat: [#1315] Fixed handling of empty characters in headers

* chore: [#1315] Adds support for multiple values to Headers and removes logic for splitting cookie string

---------

Co-authored-by: ushiboy <ushiboy.dev@gmail.com>
Co-authored-by: David Ortner <david@ortner.se>
  • Loading branch information
3 people committed Mar 18, 2024
1 parent 57bb77d commit d43d2e2
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 9 deletions.
31 changes: 22 additions & 9 deletions packages/happy-dom/src/fetch/Headers.ts
Expand Up @@ -10,7 +10,7 @@ import IHeadersInit from './types/IHeadersInit.js';
* @see https://developer.mozilla.org/en-US/docs/Web/API/Headers
*/
export default class Headers implements IHeaders {
public [PropertySymbol.entries]: { [k: string]: { name: string; value: string } } = {};
public [PropertySymbol.entries]: { [k: string]: { name: string; value: string[] } } = {};

/**
* Constructor.
Expand Down Expand Up @@ -48,11 +48,11 @@ export default class Headers implements IHeaders {
public append(name: string, value: string): void {
const lowerName = name.toLowerCase();
if (this[PropertySymbol.entries][lowerName]) {
this[PropertySymbol.entries][lowerName].value += `, ${value}`;
this[PropertySymbol.entries][lowerName].value.push(value);
} else {
this[PropertySymbol.entries][lowerName] = {
name,
value
value: [value]
};
}
}
Expand All @@ -73,7 +73,7 @@ export default class Headers implements IHeaders {
* @returns Value.
*/
public get(name: string): string | null {
return this[PropertySymbol.entries][name.toLowerCase()]?.value || null;
return this[PropertySymbol.entries][name.toLowerCase()]?.value.join(', ') ?? null;
}

/**
Expand All @@ -85,10 +85,23 @@ export default class Headers implements IHeaders {
public set(name: string, value: string): void {
this[PropertySymbol.entries][name.toLowerCase()] = {
name,
value
value: [value]
};
}

/**
* Returns an array containing the values of all Set-Cookie headers associated with a response.
*
* @returns An array of strings representing the values of all the different Set-Cookie headers.
*/
public getSetCookie(): string[] {
const entry = this[PropertySymbol.entries]['set-cookie'];
if (!entry) {
return [];
}
return entry.value;
}

/**
* Returns whether an Headers object contains a certain key.
*
Expand All @@ -106,7 +119,7 @@ export default class Headers implements IHeaders {
*/
public forEach(callback: (name: string, value: string, thisArg: IHeaders) => void): void {
for (const header of Object.values(this[PropertySymbol.entries])) {
callback(header.value, header.name, this);
callback(header.value.join(', '), header.name, this);
}
}

Expand All @@ -128,7 +141,7 @@ export default class Headers implements IHeaders {
*/
public *values(): IterableIterator<string> {
for (const header of Object.values(this[PropertySymbol.entries])) {
yield header.value;
yield header.value.join(', ');
}
}

Expand All @@ -139,7 +152,7 @@ export default class Headers implements IHeaders {
*/
public *entries(): IterableIterator<[string, string]> {
for (const header of Object.values(this[PropertySymbol.entries])) {
yield [header.name, header.value];
yield [header.name, header.value.join(', ')];
}
}

Expand All @@ -150,7 +163,7 @@ export default class Headers implements IHeaders {
*/
public *[Symbol.iterator](): IterableIterator<[string, string]> {
for (const header of Object.values(this[PropertySymbol.entries])) {
yield [header.name, header.value];
yield [header.name, header.value.join(', ')];
}
}
}
7 changes: 7 additions & 0 deletions packages/happy-dom/src/fetch/types/IHeaders.ts
Expand Up @@ -35,6 +35,13 @@ export default interface IHeaders extends Iterable<[string, string]> {
*/
set(name: string, value: string): void;

/**
* Returns an array containing the values of all Set-Cookie headers associated with a response.
*
* @returns An array of strings representing the values of all the different Set-Cookie headers.
*/
getSetCookie(): string[];

/**
* Returns whether an Headers object contains a certain key.
*
Expand Down
61 changes: 61 additions & 0 deletions packages/happy-dom/test/fetch/Headers.test.ts
Expand Up @@ -76,6 +76,14 @@ describe('Headers', () => {

expect(headers.get('Content-Type')).toBe('application/json, x-www-form-urlencoded');
});

it('Returns the value of Header as it is, set with an empty string.', () => {
const headers = new Headers();

headers.append('X-A', '');

expect(headers.get('X-A')).toBe('');
});
});

describe('set()', () => {
Expand All @@ -99,6 +107,59 @@ describe('Headers', () => {
});
});

describe('getSetCookie()', () => {
it('Returns an empty list if there is no Set-Cookie header.', () => {
const headers = new Headers();

expect(headers.getSetCookie()).toEqual([]);
});

it('Returns as a list of empty characters if the Set-Cookie header is set to an empty string.', () => {
const headers = new Headers();
headers.append('Set-Cookie', '');

expect(headers.getSetCookie()).toEqual(['']);
});

it('Returns an array of strings representing the values of all the different Set-Cookie headers.', () => {
const headers = new Headers();

headers.append('Content-Type', 'application/json');
headers.append('Set-Cookie', 'a=1');
headers.append('Set-Cookie', 'b=2; Expires=Fri, 01 Jan 2100 00:00:00 GMT');

expect(headers.getSetCookie()).toEqual([
'a=1',
'b=2; Expires=Fri, 01 Jan 2100 00:00:00 GMT'
]);

const headers2 = new Headers();

headers2.append(
'Set-Cookie',
'key=value; HttpOnly; Path=/; Expires=Fri, 01 Jan 2100 00:00:00 GMT'
);

expect(headers2.getSetCookie()).toEqual([
'key=value; HttpOnly; Path=/; Expires=Fri, 01 Jan 2100 00:00:00 GMT'
]);

const headers3 = new Headers();

headers3.append(
'Set-Cookie',
'key1=value1; HttpOnly; Path=/; Expires=Fri, 01 Jan 2100 00:00:00 GMT'
);

headers3.append('Set-Cookie', 'key2=value2; Domain=example.com; Max-Age=1');

expect(headers3.getSetCookie()).toEqual([
'key1=value1; HttpOnly; Path=/; Expires=Fri, 01 Jan 2100 00:00:00 GMT',
'key2=value2; Domain=example.com; Max-Age=1'
]);
});
});

describe('has()', () => {
it('Returns true if an header exists.', () => {
const headers = new Headers();
Expand Down

0 comments on commit d43d2e2

Please sign in to comment.