NotionRubyMapping のアップデート(14) : hkob の雑記録 (170)

はじめに

hkob の雑記録の第170回目は、ファイルブロックへの File Upload object の更新のテストを追加します。

update_block_file_file_upload

今日は FileBlock へ file_upload_object= メソッドをテスト・実装します。まずは、before で file_upload_object= を実行し、updata_block_json が正しいことを確認します。

    describe "update_block_file_file_upload" do
      let(:target) { described_class.new "abc", id: "20bd8e4e-98ab-8081-ad29-dd62726e4525" }
      let(:file_upload_object) do
        instance_double FileUploadObject, id: TestConnection::FILE_UPLOAD_IMAGE_ID, fname: "test.png"
      end

      before do
        allow(file_upload_object).to receive(:is_a?).with(FileUploadObject).and_return(true)
        target.file_upload_object = file_upload_object
      end

      it {
        expect(target.update_block_json).to eq(
          {
            type => {
              file_upload: {
                id: file_upload_object.id,
              },
            },
          },
        )
      }

FileObject は type の設定以外は全て FileBaseBlock に丸投げです。

# frozen_string_literal: true

module NotionRubyMapping
  # Notion block
  class FileBlock < FileBaseBlock
    # @return [Symbol]
    def type
      :file
    end
  end
end

FileBaseBlock に file_upload_object= を実装します。

    # @param [FileUploadObject] fuo
    def file_upload_object=(fuo)
      @file_object.file_upload_object = fuo
      @payload.add_update_block_key :file_upload
    end

これにより、テストが通過しました。

  update_block_file_file_upload
    is expected to eq {file: {file_upload: {id: "20cd8e4e98ab81aa973b00b23083c115"}}}   

続いて、dry_run のテストを追加します。

 
      context "when dry_run" do
        let(:dry_run) { target.save dry_run: true }

        it_behaves_like "dry run", :patch, :block_path, use_id: true, json_method: :update_block_json
      end

こちらは問題なくテストが通過します。

    when dry_run
      behaves like dry run
        is expected to eq "#!/bin/sh\ncurl -X PATCH 'https://api.notion.com/v1/blocks/20bd8e4e98ab8081ad29dd62726e4525' \\\n  -...ion/json' \\\n  --data '{\"file\":{\"file_upload\":{\"id\":\"20cd8e4e98ab81aa973b00b23083c115\"}}}'"                                  

最後に実際の save のテストを記述します。

       context "when save" do
        it {
          expect(target.save.url).to eq "https://prod-files-secure.s3.us-west-2.amazonaws.com/2b7b01f0-67a8-40f8-acd4-88dd2805f216/bf91dfb5-72e5-4c22-bab7-f4b9f343610f/ErSxuLeq.png-medium.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4666A5RECQ7%2F20250608%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250608T115825Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjELD%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJIMEYCIQD5ST8JlsjghfDkcWp3xihh%2B0byAjsIDkc2aW0IRkSS%2BAIhAMphaW6h2vfFunHO%2B1EGb6DlLiEJ4rreBcZiS47i4ZitKogECIn%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQABoMNjM3NDIzMTgzODA1Igwk%2FzBEoNUbyockbjkq3ANZmgEJWqJ2HdqMUyNcpJtNI4gToQ%2BcAXYswsfyNcJvV1yDazhob0KYQ%2FpniSCQPa6iORJ53Wyheg5Fo0GPvXE60bUhtcY0VKGg8U1HXVEwpATztFO6R37eAhsN6t6eN4y5ndn6CRjxVwCi5hX%2Fvfs4i6pzUDIZXvmtlSJJLt4BXdadf%2BhXADgDfL2d2qLyzdnA%2BPR7R0a9RuCAhp7cnqFbBNVrVmtgk1XUNdobV81ij%2BY6%2B2Gwf1k8j9MhaWDO1LQiUzwDErCscM%2Bp0WjREbgnfu%2F1QiFrsoJ2%2FnBvVKmFY3fPkYfwwPWCqlyjPLUqBWVdlCbhTz9UqWun%2BpXUZ9qCvWI%2FPOz43FKBvBLnefqG5tkqbyDAVh5escZisLK%2FtmV5ptWm%2FZf2U2SUeCyh8cOGLvon3%2Bf2GSfRj0T2abrWtXRzOTFJYJiMRmtHrnwGZ%2BrJmiSjU%2F5NH27e6kny6IZSIZwgW%2Fppejlfclzp2Qp0C8KDSuNZaHtcm7D5bFxN1DNGASnyz6C9pYu8QVw4vKpQXgr6rEvVHV6YXZB3EOwWAHD4%2FuA6Fg6dWJxy6N02RUZ%2B1ofSWPAIP9K67hzOfB0IhHH65TkmQDzXNMQADpB140RqyFKGlzSzOsh7bjDggZXCBjqkARQOaKDzsXc5QS2OtVCc5oPeV%2BQ%2FIYfM2uLFQQRlb4MjSRalKjK2%2Flkyn5CMLRqnapi1KzGq5KllHIuKBP6OeO6EF0Xk%2B4Mjtt%2BiFm6tofYK4T7%2BcVSUdIAR5TOF6WPN7vhHAKbGm1tZu5gbzxyKuJk5SVrSVdeakBr1N2sQTzFoGOjOcCm%2B8mkWKD7PR0nCEGTL1QnHt%2BYAKBf9AFBEZ3kdiulS&X-Amz-Signature=a12e8df1da28ef5b129263f215ec13f839c89ac1bcf6e03ba4e707117a4cc66d&X-Amz-SignedHeaders=host&x-id=GetObject"
        }
      end
    end

save の方は WebMock の stub が存在しないので、以下のようなエラーになりました。

  1) NotionRubyMapping::FileBlock update_block_file_file_upload when save 
     Failure/Error:
       response = @client.send(method) do |request|
         request.headers["Authorization"] = "Bearer #{@notion_token}"                                                               
         case method
         when :get, :delete
           request.url path, options
         when :post, :put, :patch
           request.headers["Content-Type"] = "application/json"
           request.path = path
           request.body = options.to_json unless options.empty?
         else
     
     WebMock::NetConnectNotAllowedError:
       Real HTTP connections are disabled. Please stub: PATCH https://api.notion.com/v1/blocks/20bd8e4e98ab8081ad29dd62726e4525 with body '{"file":{"file_upload":{"id":"20cd8e4e98ab81aa973b00b23083c115"}}}' with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer secret_J08RBf9SlofiMhuIeJZc6AnI5qHXwDOaq4RolJFaaZ0', 'Content-Type'=>'application/json', 'Notion-Version'=>'2022-06-28', 'User-Agent'=>'Faraday v2.13.1'} 

dry_run で送られる payload に対する stub が必要となります。これは spec_helper にて登録を行います。upload_block の下に stubs を一括作成するメソッドを用意しているので、そこに payload を追加します。FileBlock の id のページに、{} 以下の payload を入れた時に、200 の response code を返し、update_block_file_file_upload.json を返すという stub が追加されます。

    def update_block
      generate_stubs_sub :patch, __method__, :block_path, {
        (中略)
        file_file_upload: [
          "20bd8e4e98ab8081ad29dd62726e4525", 200,
          {
            file: {
              file_upload: {
                id: TestConnection::FILE_UPLOAD_IMAGE_ID,
              },
            },
          }
        ],
      }
    end

これで動作すると思ったのですが、FileUpload で送信されたブロックは、Response として内部ファイル URL として返却されてきます。その他のブロックは保存したデータをそのまま保持しておけばいいのですが、FileBlock に関してだけは、ページプロパティと同様に Response で更新する必要があるようです。

     NameError:
       undefined local variable or method 'url' for #<RSpec::ExampleGroups::NotionRubyMappingFileBlock::UpdateBlockFileFileUpload::WhenSave:0x000000011e6326c0>                                       
     # ./spec/notion_ruby_mapping/blocks/file_block_spec.rb:76:in 'block (4 levels) in <module:NotionRubyMapping>'     

そこで、block.rb における update 時に FileBaseBlock の時だけ、file_object を更新する処理を記載しました。

    # @param [Boolean] dry_run true if dry_run
    # @return [NotionRubyMapping::Base, String]
    def update(dry_run: false)
      if dry_run
        dry_run_script :patch, @nc.block_path(@id), :update_block_json
      else
        @json = @nc.update_block_request(@id, update_block_json)
        update_file_object_from_json(@json) if is_a? FileBaseBlock
      end
    end

update_file_object_from_json は親クラスである FileBaseBlock に実装しました。

    def update_file_object_from_json(json)
      @file_object = FileObject.new json: json[type]
      decode_block_caption
      @can_append = @file_object.external?
    end

これによって、save も無事にテストが通過しました。

    when save
      is expected to eq "https://prod-files-secure.s3.us-west-2.amazonaws.com/2b7b01f0-67a8-40f8-acd4-88dd2805f216/bf91dfb5-7...df1da28ef5b129263f215ec13f839c89ac1bcf6e03ba4e707117a4cc66d&X-Amz-SignedHeaders=host&x-id=GetObject"                                    

Finished in 0.09002 seconds (files took 0.35502 seconds to load)
16 examples, 0 failures

おわりに

FileBlock の更新処理も無事にテストが通過しました。明日は、ImageBlock の更新を実施します。こちらも FileBaseObject のサブクラスになっているので、テストを書くだけでよい気がします。

hkob.notion.site