diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index e05163c32f8265..befef0af658511 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -870,7 +870,14 @@ napi_status napi_get_property_names(napi_env env, v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); - auto maybe_propertynames = obj->GetPropertyNames(context); + v8::MaybeLocal maybe_propertynames = obj->GetPropertyNames( + context, + v8::KeyCollectionMode::kIncludePrototypes, + static_cast( + v8::PropertyFilter::ONLY_ENUMERABLE | + v8::PropertyFilter::SKIP_SYMBOLS), + v8::IndexFilter::kIncludeIndices, + v8::KeyConversionMode::kConvertToString); CHECK_MAYBE_EMPTY(env, maybe_propertynames, napi_generic_failure); diff --git a/test/js-native-api/test_object/test.js b/test/js-native-api/test_object/test.js index 3047b1f58dc602..d6e15dcfcef00b 100644 --- a/test/js-native-api/test_object/test.js +++ b/test/js-native-api/test_object/test.js @@ -202,3 +202,26 @@ assert.strictEqual(newObject.test_string, 'test string'); assert.strictEqual(test_object.Delete(obj, 'foo'), true); assert.strictEqual(obj.foo, 'baz'); } + +{ + // Verify that napi_get_property_names gets the right set of property names, + // i.e.: includes prototypes, only enumerable properties, skips symbols, + // and includes indices and converts them to strings. + + const object = Object.create({ + inherited: 1 + }); + + object.normal = 2; + object[Symbol('foo')] = 3; + Object.defineProperty(object, 'unenumerable', { + value: 4, + enumerable: false, + writable: true, + configurable: true + }); + object[5] = 5; + + assert.deepStrictEqual(test_object.GetPropertyNames(object), + ['5', 'normal', 'inherited']); +} diff --git a/test/js-native-api/test_object/test_object.c b/test/js-native-api/test_object/test_object.c index b6dbbd4dd33bb0..30768bdc812619 100644 --- a/test/js-native-api/test_object/test_object.c +++ b/test/js-native-api/test_object/test_object.c @@ -63,6 +63,25 @@ static napi_value GetNamed(napi_env env, napi_callback_info info) { return output; } +static napi_value GetPropertyNames(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); + + napi_valuetype value_type0; + NAPI_CALL(env, napi_typeof(env, args[0], &value_type0)); + + NAPI_ASSERT(env, value_type0 == napi_object, + "Wrong type of arguments. Expects an object as first argument."); + + napi_value output; + NAPI_CALL(env, napi_get_property_names(env, args[0], &output)); + + return output; +} + static napi_value Set(napi_env env, napi_callback_info info) { size_t argc = 3; napi_value args[3]; @@ -325,6 +344,7 @@ napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("Get", Get), DECLARE_NAPI_PROPERTY("GetNamed", GetNamed), + DECLARE_NAPI_PROPERTY("GetPropertyNames", GetPropertyNames), DECLARE_NAPI_PROPERTY("Set", Set), DECLARE_NAPI_PROPERTY("SetNamed", SetNamed), DECLARE_NAPI_PROPERTY("Has", Has),