Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added some jest-extended methods #9741

Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8f94aea
added toContainAllKeys method
nithinkjoy-tech Mar 23, 2024
f2659fb
changed method name and used jestDeepEquals
nithinkjoy-tech Mar 24, 2024
5591873
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Mar 24, 2024
f62f990
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Mar 24, 2024
9f78706
refactored and added meaningfull error message
nithinkjoy-tech Mar 24, 2024
665ec7f
formatted code
nithinkjoy-tech Mar 25, 2024
e4340c9
Added test cases
nithinkjoy-tech Mar 25, 2024
fce1b8a
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Mar 25, 2024
c587c0a
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Mar 26, 2024
32e0735
Implemented toContainValue method and added test cases
nithinkjoy-tech Mar 28, 2024
a8f7228
Implemented toContainValues() Method and added test cases
nithinkjoy-tech Mar 28, 2024
e4975d1
Refactored code
nithinkjoy-tech Mar 30, 2024
92f0978
Implemeneted toContainAllValues() method and added test cases
nithinkjoy-tech Mar 30, 2024
218f278
Added more test
nithinkjoy-tech Mar 30, 2024
4906eb7
Added length to methods
nithinkjoy-tech Mar 30, 2024
6535991
Implemented toContainAnyValues() and added tests
nithinkjoy-tech Mar 30, 2024
99e3e58
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Mar 30, 2024
db342b7
typo fix
nithinkjoy-tech Mar 31, 2024
a22108f
Merge branch 'main' into nithin/implement-missing-jestextended-methods
Electroid Apr 17, 2024
272532b
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Jun 1, 2024
6f3bb97
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Jun 1, 2024
0d88939
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Jun 5, 2024
61362e4
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Jun 6, 2024
51f0a09
Merge branch 'oven-sh:main' into nithin/implement-missing-jestextende…
nithinkjoy-tech Jun 6, 2024
cd4b217
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Jun 7, 2024
387eb27
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Jun 7, 2024
904609b
Update src/bun.js/test/expect.zig
nithinkjoy-tech Jun 8, 2024
3a1f638
Update src/bun.js/test/expect.zig
nithinkjoy-tech Jun 8, 2024
20202b1
Update src/bun.js/test/expect.zig
nithinkjoy-tech Jun 8, 2024
6e7cc9f
Update src/bun.js/test/expect.zig
nithinkjoy-tech Jun 8, 2024
ce0717e
review changes
nithinkjoy-tech Jun 8, 2024
901b010
Merge branch 'main' into nithin/implement-missing-jestextended-methods
nithinkjoy-tech Jun 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions packages/bun-types/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,21 @@ declare module "bun:test" {
* @param expected the expected value
*/
toContainKey(expected: unknown): void;
/**
* Asserts that an `object` contains all the provided keys.
*
* The value must be an object
*
* @example
* expect({ a: 'hello', b: 'world' }).toContainAllKeys(['a','b']);
* expect({ a: 'hello', b: 'world' }).toContainAllKeys(['b','a']);
* expect({ 1: 'hello', b: 'world' }).toContainAllKeys([1,'b']);
* expect({ a: 'hello', b: 'world' }).not.toContainAllKeys(['c']);
* expect({ a: 'hello', b: 'world' }).not.toContainAllKeys(['a']);
*
* @param expected the expected value
*/
toContainAllKeys(expected: unknown): void;
/**
* Asserts that an `object` contains at least one of the provided keys.
* Asserts that an `object` contains all the provided keys.
Expand All @@ -971,6 +986,78 @@ declare module "bun:test" {
*/
toContainAnyKeys(expected: unknown): void;

/**
* Asserts that an `object` contain the provided value.
*
* The value must be an object
*
* @example
* const shallow = { hello: "world" };
* const deep = { message: shallow };
* const deepArray = { message: [shallow] };
* const o = { a: "foo", b: [1, "hello", true], c: "baz" };

* expect(shallow).toContainValue("world");
* expect({ foo: false }).toContainValue(false);
* expect(deep).toContainValue({ hello: "world" });
* expect(deepArray).toContainValue([{ hello: "world" }]);

* expect(o).toContainValue("foo", "barr");
* expect(o).toContainValue([1, "hello", true]);
* expect(o).not.toContainValue("qux");

// NOT
* expect(shallow).not.toContainValue("foo");
* expect(deep).not.toContainValue({ foo: "bar" });
* expect(deepArray).not.toContainValue([{ foo: "bar" }]);
*
* @param expected the expected value
*/
toContainValue(expected: unknown): void;

/**
* Asserts that an `object` contain the provided value.
*
* The value must be an object
*
* @example
* const o = { a: 'foo', b: 'bar', c: 'baz' };
* expect(o).toContainValues(['foo']);
* expect(o).toContainValues(['baz', 'bar']);
* expect(o).not.toContainValues(['qux', 'foo']);
* @param expected the expected value
*/
toContainValues(expected: unknown): void;

/**
* Asserts that an `object` contain all the provided values.
*
* The value must be an object
*
* @example
* const o = { a: 'foo', b: 'bar', c: 'baz' };
* expect(o).toContainAllValues(['foo', 'bar', 'baz']);
* expect(o).toContainAllValues(['baz', 'bar', 'foo']);
* expect(o).not.toContainAllValues(['bar', 'foo']);
* @param expected the expected value
*/
toContainAllValues(expected: unknown): void;

/**
* Asserts that an `object` contain any provided value.
*
* The value must be an object
*
* @example
* const o = { a: 'foo', b: 'bar', c: 'baz' };
` * expect(o).toContainAnyValues(['qux', 'foo']);
* expect(o).toContainAnyValues(['qux', 'bar']);
* expect(o).toContainAnyValues(['qux', 'baz']);
* expect(o).not.toContainAnyValues(['qux']);
* @param expected the expected value
*/
toContainAnyValues(expected: unknown): void;

/**
* Asserts that an `object` contains all the provided keys.
* expect({ a: 'foo', b: 'bar', c: 'baz' }).toContainKeys(['a', 'b']);
Expand Down
98 changes: 98 additions & 0 deletions src/bun.js/bindings/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2546,6 +2546,104 @@ JSC__JSValue JSC__JSValue__keys(JSC__JSGlobalObject* globalObject, JSC__JSValue
RELEASE_AND_RETURN(scope, JSValue::encode(ownPropertyKeys(globalObject, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude)));
}

JSC__JSValue JSC__JSValue__values(JSC__JSGlobalObject* globalObject, JSC__JSValue objectValue)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);

JSC::JSValue targetValue = JSC::JSValue::decode(objectValue);
if (targetValue.isUndefinedOrNull())
return throwVMTypeError(globalObject, scope, "Object.values requires that input parameter not be null or undefined"_s);
JSC::JSObject* target = targetValue.toObject(globalObject);
RETURN_IF_EXCEPTION(scope, { });

if (!target->staticPropertiesReified()) {
target->reifyAllStaticProperties(globalObject);
RETURN_IF_EXCEPTION(scope, { });
}

{
JSC::MarkedArgumentBuffer namedPropertyValues;
bool canUseFastPath = false;
if (!target->canHaveExistingOwnIndexedGetterSetterProperties() && !target->hasNonReifiedStaticProperties()) {
JSC::Structure* targetStructure = target->structure();
if (targetStructure->canPerformFastPropertyEnumerationCommon()) {
canUseFastPath = true;
targetStructure->forEachProperty(vm, [&](const PropertyTableEntry& entry) -> bool {
if (entry.attributes() & PropertyAttribute::DontEnum)
return true;

if (entry.key()->isSymbol())
return true;

namedPropertyValues.appendWithCrashOnOverflow(target->getDirect(entry.offset()));
return true;
});
}
}

if (canUseFastPath) {
JSC::Structure* arrayStructure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
JSC::MarkedArgumentBuffer indexedPropertyValues;
if (target->canHaveExistingOwnIndexedProperties()) {
target->forEachOwnIndexedProperty<JSC::JSObject::SortMode::Ascending>(globalObject, [&](unsigned, JSC::JSValue value) {
indexedPropertyValues.appendWithCrashOnOverflow(value);
return IterationStatus::Continue;
});
}
RETURN_IF_EXCEPTION(scope, { });

{
JSC::ObjectInitializationScope initializationScope(vm);
JSC::JSArray* result = nullptr;
if (LIKELY(result = JSC::JSArray::tryCreateUninitializedRestricted(initializationScope, nullptr, arrayStructure, indexedPropertyValues.size() + namedPropertyValues.size()))) {
for (unsigned i = 0; i < indexedPropertyValues.size(); ++i)
result->initializeIndex(initializationScope, i, indexedPropertyValues.at(i));
for (unsigned i = 0; i < namedPropertyValues.size(); ++i)
result->initializeIndex(initializationScope, indexedPropertyValues.size() + i, namedPropertyValues.at(i));
return JSC::JSValue::encode(result);
}
}
throwOutOfMemoryError(globalObject, scope);
return { };
}
}

JSC::JSArray* values = JSC::constructEmptyArray(globalObject, nullptr);
RETURN_IF_EXCEPTION(scope, { });

JSC::PropertyNameArray properties(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
target->methodTable()->getOwnPropertyNames(target, globalObject, properties, DontEnumPropertiesMode::Include);
RETURN_IF_EXCEPTION(scope, { });

unsigned index = 0;
auto append = [&] (JSGlobalObject* globalObject, PropertyName propertyName) {
PropertySlot slot(target, PropertySlot::InternalMethodType::GetOwnProperty);
bool hasProperty = target->methodTable()->getOwnPropertySlot(target, globalObject, propertyName, slot);
RETURN_IF_EXCEPTION(scope, void());
if (!hasProperty)
return;
if (slot.attributes() & PropertyAttribute::DontEnum)
return;

JSC::JSValue value;
if (LIKELY(!slot.isTaintedByOpaqueObject()))
value = slot.getValue(globalObject, propertyName);
else
value = target->get(globalObject, propertyName);
RETURN_IF_EXCEPTION(scope, void());

values->putDirectIndex(globalObject, index++, value);
};

for (const auto& propertyName : properties) {
append(globalObject, propertyName);
RETURN_IF_EXCEPTION(scope, { });
}

return JSC::JSValue::encode(values);
}

bool JSC__JSValue__hasOwnProperty(JSC__JSValue jsValue, JSC__JSGlobalObject* globalObject, ZigString key)
{
JSC::VM& vm = globalObject->vm();
Expand Down
20 changes: 16 additions & 4 deletions src/bun.js/bindings/bindings.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3887,8 +3887,8 @@ pub const JSValue = enum(JSValueReprInt) {
return cppFn("createEmptyArray", .{ global, len });
}

pub fn putRecord(value: JSValue, global: *JSGlobalObject, key: *ZigString, values: [*]ZigString, values_len: usize) void {
return cppFn("putRecord", .{ value, global, key, values, values_len });
pub fn putRecord(value: JSValue, global: *JSGlobalObject, key: *ZigString, values_array: [*]ZigString, values_len: usize) void {
return cppFn("putRecord", .{ value, global, key, values_array, values_len });
}

fn putZigString(value: JSValue, global: *JSGlobalObject, key: *const ZigString, result: JSC.JSValue) void {
Expand Down Expand Up @@ -4307,11 +4307,11 @@ pub const JSValue = enum(JSValueReprInt) {
return String.init(buf.toOwnedSliceLeaky()).toJS(globalThis);
}

pub fn fromEntries(globalThis: *JSGlobalObject, keys_array: [*c]ZigString, values: [*c]ZigString, strings_count: usize, clone: bool) JSValue {
pub fn fromEntries(globalThis: *JSGlobalObject, keys_array: [*c]ZigString, values_array: [*c]ZigString, strings_count: usize, clone: bool) JSValue {
return cppFn("fromEntries", .{
globalThis,
keys_array,
values,
values_array,
strings_count,
clone,
});
Expand All @@ -4324,6 +4324,17 @@ pub const JSValue = enum(JSValueReprInt) {
});
}

pub fn values(_: JSValue, globalThis: *JSGlobalObject, value: JSValue) JSValue {
return cppFn("values", .{
globalThis,
value,
});
}

pub fn getKeys(_: JSValue, globalThis: *JSGlobalObject, value: JSC.JSValue) JSValue {
return keys(globalThis, value);
}

pub fn hasOwnPropertyValue(this: JSValue, globalThis: *JSGlobalObject, value: JSC.JSValue) bool {
// TODO: add a binding for this
return hasOwnProperty(this, globalThis, value.getZigString(globalThis));
Expand Down Expand Up @@ -5536,6 +5547,7 @@ pub const JSValue = enum(JSValueReprInt) {
"jsUndefined",
"jsonStringify",
"keys",
"values",
"kind_",
"parseJSON",
"put",
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/headers.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/bun.js/bindings/headers.zig

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading