Repository: capricorn86/happy-dom (ts)

Issue:
regression: assign of window.location.href
**Describe the bug**
A clear and concise description of what the bug is.

Starting with version 7.8.0, setting the `href` property like this:
```
window.location.href = '/foo'
```

Will throw an exception: `ERR_INVALID_URL`.

**To Reproduce**
Steps to reproduce the behavior:
1. Create a test with happy-dom
2. In the test, insert `window.location.href = '/foo'`
3. See error `ERR_INVALID_URL`

**Expected behavior**
I can set the `href` property using a string which doest not represent a full url, in the same exact way in which both chrome and firefox works.

**Screenshots**
<img width="548" alt="image" src="https://user-images.githubusercontent.com/6383527/206861764-f38db7fe-d3a8-4303-90a2-abd4cf6767ce.png">

**Device:**
 - OS: OS X
 - Browser: Vitest
 - Version: v0.25.6

**Additional context**
This happens using happy-dom during tests.


Pull request:
#678@patch: Assign of window.location.href.
Fixes #678.

Patch:
diff --git a/packages/happy-dom/src/location/Location.ts b/packages/happy-dom/src/location/Location.ts
index 05898745..bc9a07a8 100644
--- a/packages/happy-dom/src/location/Location.ts
+++ b/packages/happy-dom/src/location/Location.ts
@@ -1,4 +1,6 @@
 import { URL } from 'url';
+import DOMException from '../exception/DOMException';
+import DOMExceptionNameEnum from '../exception/DOMExceptionNameEnum';
 
 /**
  *
@@ -11,6 +13,35 @@ export default class Location extends URL {
 		super('about:blank');
 	}
 
+	/**
+	 * Override set href.
+	 */
+	// @ts-ignore
+	public set href(value: string) {
+		try {
+			super.href = this.hostname ? new URL(value, this).href : value;
+		} catch (e) {
+			if (this.hostname) {
+				throw new DOMException(
+					`Failed to construct URL from string "${value}".`,
+					DOMExceptionNameEnum.uriMismatchError
+				);
+			} else {
+				throw new DOMException(
+					`Failed to construct URL from string "${value}" relative to URL "${super.href}".`,
+					DOMExceptionNameEnum.uriMismatchError
+				);
+			}
+		}
+	}
+
+	/**
+	 * Override set href.
+	 */
+	public get href(): string {
+		return super.href;
+	}
+
 	/**
 	 * Replaces the current resource with the one at the provided URL. The difference from the assign() method is that after using replace() the current page will not be saved in session History, meaning the user won't be able to use the back button to navigate to it.
 	 *
@@ -29,7 +60,7 @@ export default class Location extends URL {
 	 * @see this.replace()
 	 */
 	public assign(url: string): void {
-		this.replace(url);
+		this.href = url;
 	}
 
 	/**


Test patch:
diff --git a/packages/happy-dom/test/location/Location.test.ts b/packages/happy-dom/test/location/Location.test.ts
index 59c701ea..45ddb7a8 100644
--- a/packages/happy-dom/test/location/Location.test.ts
+++ b/packages/happy-dom/test/location/Location.test.ts
@@ -1,3 +1,5 @@
+import DOMException from '../../src/exception/DOMException';
+import DOMExceptionNameEnum from '../../src/exception/DOMExceptionNameEnum';
 import Location from '../../src/location/Location';
 
 const HREF = 'https://google.com/some-path/?key=value&key2=value2#hash';
@@ -30,4 +32,30 @@ describe('Location', () => {
 			expect(location.href).toBe(HREF);
 		});
 	});
+
+	describe('href', () => {
+		it('Successully sets a relative URL.', () => {
+			location.href = HREF;
+			expect(location.href).toBe(HREF);
+			location.href = '/foo';
+			expect(location.href).toBe('https://google.com/foo');
+		});
+
+		it('Fails when it is not possible to construct a relative URL.', () => {
+			let error: Error | null = null;
+
+			try {
+				location.href = '/foo';
+			} catch (e) {
+				error = e;
+			}
+
+			expect(error).toEqual(
+				new DOMException(
+					`Failed to construct URL from string "/foo" relative to URL "about:blank".`,
+					DOMExceptionNameEnum.uriMismatchError
+				)
+			);
+		});
+	});
 });