js_handle_spec.rb 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. require 'spec_helper'
  2. RSpec.describe Puppeteer::JSHandle do
  3. describe 'Page#evaluate_handle' do
  4. it 'should work' do
  5. window_handle = page.evaluate_handle('() => window')
  6. expect(window_handle).to be_a(Puppeteer::JSHandle)
  7. end
  8. it 'should return the RemoteObject' do
  9. window_handle = page.evaluate_handle('() => window')
  10. expect(window_handle.remote_object).to be_a(Puppeteer::RemoteObject)
  11. end
  12. it 'should accept object handle as an argument' do
  13. navigator_handle = page.evaluate_handle('() => navigator')
  14. text = page.evaluate('(e) => e.userAgent', navigator_handle)
  15. expect(text).to include('Mozilla')
  16. end
  17. it 'should accept object handle to primitive types' do
  18. handle = page.evaluate_handle('() => 5')
  19. expect(page.evaluate('(e) => Object.is(e, 5)', handle)).to eq(true)
  20. end
  21. it 'should accept object handle to unserializable value' do
  22. handle = page.evaluate_handle('() => Infinity')
  23. expect(page.evaluate('(e) => Object.is(e, Infinity)', handle)).to eq(true)
  24. end
  25. it 'should use the same JS wrappers / should work with primitives' do
  26. handle = page.evaluate_handle('() => { globalThis.FOO = 123; return window; }')
  27. expect(page.evaluate('(e) => e.FOO', handle)).to eq(123)
  28. end
  29. end
  30. describe '#property' do
  31. it 'should work' do
  32. handle = page.evaluate_handle('() => ({ one: 1, two: 2, three: 3 })')
  33. expect(handle['two'].json_value).to eq(2)
  34. expect(handle.property('two').json_value).to eq(2)
  35. end
  36. end
  37. describe '#json_value' do
  38. it 'should work' do
  39. handle = page.evaluate_handle("() => ({ foo: 'bar' })")
  40. json = handle.json_value
  41. expect(json).to eq({ 'foo' => 'bar' })
  42. end
  43. it_fails_firefox 'should not work with dates' do
  44. date_handle = page.evaluate_handle("() => new Date('2017-09-26T00:00:00.000Z')")
  45. json = date_handle.json_value
  46. expect(json).to eq({})
  47. end
  48. it 'should throw for circular objects' do
  49. window_handle = page.evaluate_handle('window')
  50. if Puppeteer.env.chrome?
  51. expect { window_handle.json_value }.to raise_error(/Object reference chain is too long/)
  52. elsif Puppeteer.env.firefox?
  53. expect { window_handle.json_value }.to raise_error(/Object is not serializable/)
  54. end
  55. end
  56. end
  57. describe '#properties' do
  58. it 'should work' do
  59. handle = page.evaluate_handle("() => ({ foo: 'bar' })")
  60. properties = handle.properties
  61. expect(properties['foo'].json_value).to eq('bar')
  62. end
  63. it 'should return even non-own properties' do
  64. js = <<~JAVASCRIPT
  65. () => {
  66. class A {
  67. constructor() {
  68. this.a = '1';
  69. }
  70. }
  71. class B extends A {
  72. constructor() {
  73. super();
  74. this.b = '2';
  75. }
  76. }
  77. return new B();
  78. }
  79. JAVASCRIPT
  80. handle = page.evaluate_handle(js)
  81. properties = handle.properties
  82. expect(properties['a'].json_value).to eq('1')
  83. expect(properties['b'].json_value).to eq('2')
  84. end
  85. end
  86. describe '#as_element' do
  87. it 'should work' do
  88. handle = page.evaluate_handle("() => document.body")
  89. element = handle.as_element
  90. expect(element).to be_a(Puppeteer::ElementHandle)
  91. end
  92. it 'should return null for non-elements' do
  93. handle = page.evaluate_handle('() => 2')
  94. element = handle.as_element
  95. expect(element).to be_nil
  96. end
  97. it 'should return ElementHandle for TextNodes' do
  98. page.content = '<div>ee!</div>'
  99. handle = page.evaluate_handle("() => document.querySelector('div').firstChild")
  100. element = handle.as_element
  101. expect(element).to be_a(Puppeteer::ElementHandle)
  102. expect(page.evaluate("(e) => e.nodeType === Node.TEXT_NODE", element)).to eq(true)
  103. end
  104. end
  105. describe '#to_s' do
  106. it 'should work for primitives' do
  107. number_handle = page.evaluate_handle("() => 2")
  108. expect(number_handle.to_s).to eq("JSHandle:2")
  109. string_handle = page.evaluate_handle("() => 'a'")
  110. expect(string_handle.to_s).to eq("JSHandle:a")
  111. end
  112. it 'should work for complicated objects' do
  113. handle = page.evaluate_handle('() => window')
  114. expect(handle.to_s).to eq('JSHandle@object')
  115. end
  116. [
  117. [:integer, '12', 'JSHandle:12'],
  118. [:boolean, 'true', 'JSHandle:true'],
  119. [:undefined, 'undefined', 'JSHandle:undefined'],
  120. [:string, '"foo"', 'JSHandle:foo'],
  121. [:symbol, 'Symbol()', 'JSHandle@symbol'],
  122. [:map, 'new Map()', 'JSHandle@map'],
  123. [:set, 'new Set()', 'JSHandle@set'],
  124. [:null, 'null', 'JSHandle:undefined'], # in JS, 'JSHandle:undefined'. But Ruby can't distinguish null from undefined.
  125. [:regexp, '/foo/', 'JSHandle@regexp'],
  126. [:weakset, 'new WeakSet()', 'JSHandle@weakset'],
  127. [:error, 'new Error()', 'JSHandle@error'],
  128. [:typedarray, 'new Int32Array()', 'JSHandle@typedarray'],
  129. [:proxy, 'new Proxy({}, {})', 'JSHandle@proxy'],
  130. ].each do |type, js, expected_string|
  131. it "should work with different subtypes: [#{type}]" do
  132. expect(page.evaluate_handle(js).to_s).to eq(expected_string)
  133. end
  134. end
  135. end
  136. end