diff --git a/src/AngleSharp.Js.Tests/DomTests.cs b/src/AngleSharp.Js.Tests/DomTests.cs index e14fe45..bfd1e4c 100644 --- a/src/AngleSharp.Js.Tests/DomTests.cs +++ b/src/AngleSharp.Js.Tests/DomTests.cs @@ -82,5 +82,33 @@ public async Task ConsoleKeepsPropertiesAssignedToIt() var result = await "(function () { window.console.marker = 'kept'; return window.console.marker; })()".EvalScriptAsync(); Assert.AreEqual("kept", result); } + + [Test] + public async Task InheritedMemberIsNotAnOwnPropertyOfTheNode() + { + var result = await "document.createElement('div').hasOwnProperty('firstChild')".EvalScriptAsync(); + Assert.AreEqual("False", result); + } + + [Test] + public async Task InheritedMemberIsStillVisibleOnTheNode() + { + var result = await "('firstChild' in document.documentElement) + ',' + (typeof document.documentElement.appendChild)".EvalScriptAsync(); + Assert.AreEqual("true,function", result); + } + + [Test] + public async Task InheritedAccessorStillReadsAndWrites() + { + var result = await "(function () { var d = document.createElement('div'); d.id = 'jint'; return d.id; })()".EvalScriptAsync(); + Assert.AreEqual("jint", result); + } + + [Test] + public async Task AssignedPropertyIsReportedConsistently() + { + var result = await "(function () { var d = document.createElement('div'); d.custom = 1; return d.hasOwnProperty('custom') + ',' + Object.getOwnPropertyNames(d).join(); })()".EvalScriptAsync(); + Assert.AreEqual("true,custom", result); + } } } diff --git a/src/AngleSharp.Js/Proxies/DomNodeInstance.cs b/src/AngleSharp.Js/Proxies/DomNodeInstance.cs index dba951b..d70ba4c 100644 --- a/src/AngleSharp.Js/Proxies/DomNodeInstance.cs +++ b/src/AngleSharp.Js/Proxies/DomNodeInstance.cs @@ -67,18 +67,14 @@ public DomEventInstance.Registration RemoveEventHandler(DomEventInstance ev) public override PropertyDescriptor GetOwnProperty(JsValue property) { - if (Prototype is DomPrototypeInstance prototype) + // An indexer is the only thing that can turn into an own property of the node + // itself. The members of the DOM interface live on the prototype, so finding + // them is the engine's job - answering them here would make the node claim + // every inherited member as its own. + if (Prototype is DomPrototypeInstance prototype && + prototype.TryGetFromIndex(_value, property.ToString(), out var descriptor)) { - if (prototype.TryGetFromIndex(_value, property.ToString(), out var descriptor)) - { - return descriptor; - } - - var prototypeProperty = prototype.GetOwnProperty(property); - if (prototypeProperty != PropertyDescriptor.Undefined) - { - return prototypeProperty; - } + return descriptor; } return base.GetOwnProperty(property);